DTMやってる人ならおなじみだとは思うけど、OSXになってからオーディオ周りが「Core Audio」で統一された。 iphoneで音を鳴らす方法はいくつかあるが、とりあえず概念的なものはここの記事が分かりやすい。 楽器アプリの作り方 CoreAudioは、以下のフレームワークから形成されている。
・AVFoundation:オーディオプレイヤーを利用するためのフレームワーク ・Audio Toolbox、Audio Unit:OSX独自のフレームワーク ・OpenAL:ゲームアプリケーション等、OpenGLのサウンド版みたいなもので3D音響が扱える
作成するアプリによって利用するフレームワークが変わってくる。
Audio Toolboxに含まれる一番シンプルなサービスで、短いサウンドを再生するのに適している。 SystemSoundIDを割り当てて、オーディオファイル(.aif)を再生する。
サウンドデータのバッファを複数用意してキューを作成し、コールバックで音を再生する。 再生する前に、メモリに必要最小限のデータを用意するので効率が良い。 しかしこの方式だとデータを用意する時間、いわゆる「レイテンシー」が発生する。
標準化されたAPIが多数用意されており、オーディオ管理には3つの要素から構成されている。 ・Buffer ・Source ・Listener 再生ファイルはリニアPCMの方式で受け渡す必要がある。
SafariでURLを開くのを調べてたけど、Google先生に聞いてもなかなか見つからなかった。
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://hoge.com/"]];
openURLはNSURLのメソッドと思いきや、UIApplicationなんですねぇ。
gvim-kaoriyaのOSX版をいつも忘れてしまうのでメモ。
■macvim macvim-kaoriya
Windows版同様に複数ファイル開け、尚かつvimの癖に コピ&ペーストのショートカットも直接使えたりする。
Google Chromeのver 6だとBASIC認証のページにアクセスする度に、毎回ダイアログが表示されてしまいます。
パスワード保存のダイアログが表示されない
のが原因のようで、ver 7 betaでは解決されている模様。
ただ、https経由だとこのバグが修正されていないみたいだ。 うーん。
NSFetchedResultsControllerを利用して、UITableViewでセクション別にソートしてデータの更新/表示する処理。 相当ハマりましたが、少しずつ理解できたので更新。
NSFetchedResultsController でグルーピング(Section分け)
このサイトでも勉強しましたが、実際やってみると原因追及に相当時間がかかりました。
(1) fetchedResultsControllerとUITableViewのデータ整合性 (2) setSortDescriptorsとsectionNameKeyPathによるデータ整合性 (3) didChangeObjectのアニメーション処理によるデータ整合性 (4) managedObjectContextの管理ミス
アプリケーションからmanagedObjectContextを取得する必要があります。
- (void)viewDidLoad {
[super viewDidLoad];
UserAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
self.managedObjectContext = [appDelegate managedObjectContext];
}
これで、クラス内のmanagedObjectContextのアクセスは
[self managedObjectContext]
で統一できます。
@synthesize fetchedResultsController=fetchedResultsController_;
@synthesize managedObjectContext=managedObjectContext_;
@synthesize userListViewController;
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController_) {
return fetchedResultsController_;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"User"
inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"indexName" ascending:YES];
NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, sortDescriptor2, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:[self managedObjectContext]
sectionNameKeyPath:@"indexName"
cacheName:nil
];
aFetchedResultsController.delegate = userListViewController;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
NSError *error = nil;
if (![fetchedResultsController_ performFetch:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return fetchedResultsController_;
}
上記の例では、データ取得の際、User EntityのindexNameとnameの順でソートしています。 indexNameは、データ一覧をセクション別にグルーピングする為に、nameの先頭1文字を保存したカラムです。
Userデータ一覧を先頭文字(indexName)でセクション分けして取得するには、sectionNameKeyPathにindexNameを設定します。 これは相当便利です。
ただし、setSortDescriptorsでソートした結果と、sectionNameKeyPathでソートした結果の並び順が必ず同じでなければなりません。
つまり、データ追加、削除、データ変更による並び替えを考慮して設計しなければいけません。 双方のセクション数、データ数、indexPathが狂ったらアウトです。
fetchedResultsControllerを実装したクラスでは、ユーザ一覧のUITableViewを持たない設計にしているので(Userデータ一元管理)、 ユーザ一覧のクラスUserListViewControllerを、delegateとして設定しています。
aFetchedResultsController.delegate = userListViewController;
もし、ユーザ一覧とfetchedResultsControllerの実装が同じクラスであれば、通常通りselfです。 どちらにするかは悩みどころです。 fetchedResultsControllerとUITalbeViewは同じクラス内で実装した方が良かったかな?と思ったりもします。
aFetchedResultsController.delegateを設定しているので、これらメソッドが自動で呼び出されます。
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [[self.delegate.fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[[self.delegate.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
User *user = [self.delegate.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [[user valueForKey:@"name"] description];
return cell;
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [NSString stringWithFormat:@"%@", [[[self.delegate.fetchedResultsController sections] objectAtIndex:section] name], nil];
}
データ取得は常に、self.delegate.fetchedResultsControllerを経由しています。 NSFetchedResultsControllerには、面倒なデータ取得メソッドが用意されているのでこれが重宝される理由かと思います。
UITalbeVIewにアニメーションをつけないのであれば、以下のコーディングで問題ないと思います。
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = userTableView;
[tableView reloadData];
}
が、UITalbeVIewアニメーションをつける場合、用意された雛形をそのまま利用するとアプリが落ちる事があります。
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = userTableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView reloadData];
//[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
//[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
自分が陥ったのは、ソートやセクションの増減が発生した場合で、コメントアウトした部分が問題でした。 例えば、managedObjectContext上でAセクションが削除されても、 UITalbeViewのレンダリング途中でデータ不整合が起こりアプリが終了します。
NSManagedObjectContextを利用していると、自分の設計やコーディングによりアプリが落ちる事が多々ありました(^^;)
NSManagedObjectContextのデータを変更するだけ(saveしない)で、fetchedResultsControllerが呼ばれてしまったり、色々な画面を行き来しているうちにメモリが解放されてたりと頭を悩ませます。
こればかりは経験値もありますが、シンプルなベストプラクティスな設計を身につけたいものです。
CoreDataの更新処理でかなりハマりました(>_<)
NSFetchedResultsControllerを利用してCoreDataの更新やフェッチ処理をしていますが、 ソートをかけた状態でデータ更新処理がうまくいかない事があります。
上記の項目名を変更する際、並び順が変わるような更新が発生した時にエラーになりました。
Assertion failure in -[UITableView _endCellAnimationsWithContext:]
エラーからするとUITableViewのnumberOfSectionsInTableView、numberOfRowsInSection等で更新処理が正常にいっていないようです。
更新後にUITableViewのメソッドがfetchedResultsControllerを読んだ時点で、ManagedObjectContextの不整合が起きているものと思われます。
Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (5) must be equal to the number of rows contained in that section before the update (5), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted). with userInfo (null)
更にエラーを読み解いてくと、NSManagedObjectContextObjectsDidChangeNotificationが発生した時に、UITableViewのsectionが0になってしまいます。 また更新前と更新後のUITableViewのrowsの数も異なっているようです。
で、同じようにハマっている人がいました。 ・Study CoreData 19 ~最悪のシナリオ~ ・-[NSFetchedResultsController performFetch:] でクラッシュ
うーん、ちょっと大変そう。 ログを追跡してわかりましたが、NSManagedObjectContextをsaveする以前に、NSManagedObjectのデータを変更し、ソートが発生するような一覧になった時にこの現象が起きるようです。 NSFetchedResultsControllerとUITableViewのメソッドで何が行われているか?もう少し理解が必要かも。
ちなみに、UITableViewをNSManagedObjectContextで管理せず、UITableView用のNSArrayで管理すれば問題は回避できそうだけど、何だか本末転倒な気がする。 NSManagedとNSArrayでわけて管理するとメモリの無駄使いや、混乱して違うバグを生む可能性も否めない。
とりあえず、didChangeObjectの処理に問題がありそうなので、そこから手をつけていくことにした。
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
並び替えが発生するデーター更新の場合、NSFetchedResultsChangeMoveを経由することになり、どうやらdeleteRowsAtIndexPaths、InsertRowsAtIndexPathsの処理で不整合になるようです。
case NSFetchedResultsChangeMove:
[tableView reloadData]
break;
とりあえず、行を削除せずにUITableViewのデータをリロードする事で回避できましたが、今度はUITableViewのdidSelectRowAtIndexPathの処理で整合性が・・・
そこで、fetchedResultsControllerメソッドの雛形の部分で、fetchedResultsController_をキャッシュしているような箇所があったので、コメントアウトしてみた。
if (fetchedResultsController_ != nil) {
//return fetchedResultsController_;
}
これで、didSelectRowAtIndexPathクリック後の処理もうまくいったが、毎回NSFetchRequestを発行する事になります・・・。
----2010/09/01追記 「return fetchedResultsController_」のコメントアウトは、しなくても良かったです。 (当然と言えば当然か・・・) fetchedResultsControllerを複数のクラスで記述したり、共有したりしていた自分のバグでした。
今回の例はセクションを利用していないので、セクションを利用する場合はUITableViewとの連携がもっと大変です。 肝は、
fetchedResultsControllerのソート順とUITableViewのソート順が常に一致している
ことです。
UITabBarControllerとUINavigationControllerでレイアウトをした際、 状況に寄ってUITableViewのセルがTabBarに隠れてしまうことがある。 ※最下段のセルがTabBarに隠れてしまった
はてなでこんな記事があったが、 UITabBarController + UINavigationController + UITableViewという画面構成のときに、次の画面でタブバーを消すようにしていると、前の画面に戻ってきたとき、テーブルの一番下が隠れる。 うーん、個人的にはコーディングでNIBを位置調整するのはバグを生みそうだし、MVCに反してる気がする ・・・って事で、何とかIBだけで対処方法を模索する。
ちなみに、画面構成は以下の階層(親から順)になっている
(1) Window <- UITabBarController - UIViewController(複数) (2) View <- Controller(Show Navigation Bar) - UIViewController (3) UITableView
まず、(1)のUIViewControllerは、レイアウトの高さは数値で設定できない。
ViewControllerのAttributesには、Wants Full ScreenやResize View From NIBのチェックがある。 Wants Full Screenにチェックすると、UITableViewのセルはきっちり収まった。 が・・・今度は(2)のNavigation ControllerのTop Barの上部が隠れてしまう。
Simulated User Interface Elementsでも色々調整してみる。 どうも上手くいかない。 というか、こいつの使い道がよくわからない。。。
(3)のレイアウトでUITableView単独で表示するのではなくUIView - UITableViewにしてやり、 UITableViewの高さをSize & Positioningで調整してみた。 (自分の場合、365pxくらいでした)
また、ViewSizeのAutoSizingがデフォルトで有効になっている。 赤い線をクリックすると無効になります。 この場合、オブジェクト内の縦線(高さ相当)を無効にしてみました。
多分、これで回避できるとは思うけど、各設定がちゃんと把握できてないのですっきりしないです。
おぉ、Core Dataでマイグレーションが使えるんだ!
・(旧) Cocoaの日々 CoreData - マイグレーション ・Core Data Migration Problems? ・Core Dataの自動マイグレーション
確かにマイグレーションできないと管理が大変・・・と言うか、データモデルが少しでも変更されるとアプリが起動しなくなる(アプリを削除すれば起動するがデータが消える)のでマイグレーションは必須です。
とりあえず、今作成しているアプリで調査がたら試してます。
(1) xcdatamodelを開く。 (2) 設計>データモデル>モデルバージョンを追加 を選択する。
(3) xcdatamodelが追加される。
(4) 新規ファイル> ResourseからMapping Modelを選択する。
(5) ファイル名をつけて【次へ】進む。 ※ファイル名はバージョンと絡めた方が、見た目はわかりやすいかも知れない
(5) ソースモデルの設定、ディスティネーションの設定を選択し【完了】する。 ※ソースモデルは現在のバージョンのxcdatamodel、ディスティネーションは次のバージョンのxcdatamodel
(6) 作成したMapping Modelファイルを開く。
【差分を表示】をクリックすると、バージョンの差分が表示されている。
(7) 最新のxcdatamodelを開き、設計>データモデル>現在のバージョンを設定を選択する。
これで、モデルのバージョン移行が完了です。 ・・・と、アプリをビルドしてみると
落ちてしまいます
CoreDataでプロジェクトを作成すると、persistentStoreCoordinator等の雛形を作成してくれる訳だけど、 なぜかマイグレーションで管理した場合は、以下のoptionsのコードを記述しないとエラーになってしまう。
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
initWithManagedObjectModelするときに、optionsを設定してやる。
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
NSLog(@"----- App persistentStoreCoordinator -----");
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSURL *storeURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"iMusicScore.sqlite"]];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
NSError *error = nil;
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return persistentStoreCoordinator_;
}
これで、モデルのバージョン移行が完了です! 勿論、旧バージョンにも戻せます。
さて、うまく動作したはいいけど、モデルのクラスファイルが更新の仕方がわからないです。 今は、手動でモデルを置き換えてます。
ここら辺は、調査しないといけないとこです。 わかったら、またトピックにする予定。
iPhoneホームのようなページングが、かなりお手軽に作成できるのでちょっとびっくり。
基本的にはUIScrollViewだけで完結しますが、UIPageControlで現在のページ状況を表示できます。 ちなみにUIPageControlはUIViewの子です。
ポイントはUIScrollViewのframeのサイズを利用して横スクロールさせる、つまり映画のフレーム方式です。 Flash制作者の人ならよく使う技ですけど、ごり押しコードでなくもっとシステマティックですw
表示するページコンテンツをいつ追加するかはアプリによると思いますが、 とりあえず全ページ作られた状態でスクロールする方法で。
まず、定義から。
@interface HomeViewController : UIViewController {
UIScrollView *scrollView;
UIView *pageView;
UIPageControl *pageControl;
}
@property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
@property (nonatomic, retain) IBOutlet UIView *pageView;
@property (nonatomic, retain) IBOutlet UIPageControl *pageControl;
@end
UIViewControllerのViewにscrollViewとpageControlを追加します。 さらにscrollViewでページングで表示するViewをpageViewとしました。 あとはスクロールの機能を使うので、UIScrollViewDelegateの追加を。
(1)scrollViewでページングで表示するView(pageView)を追加する ※PageViewは、IBOutlet *pageViewにバインド
このViewに1ページずつコンテンツを作ります。 サイズは320px/1ページになるかと思います。
(2) ViewにUIScrollViewとUIPageControlを配置する ※ScrollViewは、IBOutlet *scrollViewにバインド ※PageControlは、IBOutlet *pageControlにバインド
(3) UIScrollViewのdelegateをFile's Ownerにバインドする
delegateしておくことで自動的にscrollViewDidScrollが呼ばれます。 ちなみに、UIScrollViewのDelegateメソッドを調べると、
- (void)scrollViewDidScroll:(UIScrollView *)scrollView; // any offset changes
- (void)scrollViewDidZoom:(UIScrollView *)scrollView __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_2); // any zoom scale changes
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView; // called on start of dragging (may require some time and or distance to move)
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate; // called on finger up if user dragged. decelerate is true if it will continue moving afterwards
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView; // called on finger up as we are moving
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView; // called when scroll view grinds to a halt
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView; // called when setContentOffset/scrollRectVisible:animated: finishes. not called if not animating
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView; // return a view that will be scaled. if delegate returns nil, nothing happens
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_2); // called before the scroll view begins zooming its content
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale; // scale between minimum and maximum. called after any 'bounce' animations
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView; // return a yes if you want to scroll to the top. if not defined, assumes YES
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView; // called when scrolling animation finished. may be called immediately if already at top
これで、ズームもいけちゃうっぽい!?
次に実装です。
#import "HomeViewController.h"
@implementation HomeViewController
@synthesize scrollView;
@synthesize pageView;
@synthesize pageControl;
- (void)viewDidLoad {
[super viewDidLoad];
scrollView.pagingEnabled = YES;
scrollView.contentSize = CGSizeMake(640, 0);
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.scrollsToTop = YES;
pageControl.numberOfPages = 2;
pageControl.currentPage = 0;
[scrollView addSubview:pageView];
}
- (void)scrollViewDidScroll:(UIScrollView *)sender {
CGFloat pageWidth = scrollView.frame.size.width;
pageControl.currentPage = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
}
@end
実は
scrollViewのcontentSizeの設定と、pagingEnabledを有効する
だけでページングできてしまうのです。素晴らしい! 始めはこれを知らずに、scrollViewの位置とかで計算しようとしてましたw
UIScrollView scrollViewDidScrollを利用して、pageControlに現在のページ情報を設定します。 scrollViewの幅を計算して出してるところが力技っぽいけど。 将来的には、ページング周りのAPIが充実してくれるとうれしいですね。 (実はもうあったり!?)
PHPというか、正規表現をよく忘れるのでメモ(^^;)
preg_match("/^[0-9]{3}-[0-9]{4}$/", $value);
preg_match("/^[0-9]{2,4}-[0-9]{2,4}-[0-9]{3,4}$/", $value);
preg_match("/^\w+[\w\-\.]*@([\w\-]+\.)+\w{2,4}$/", $value);
preg_match("|^[0-9a-z_./?-]+@([0-9a-z-]+\.)+[0-9a-z-]+$", $value);
preg_match('/^(https?|ftp)(:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)$/', $url);
preg_match('@^(?:http://)?([^/]+)@i',$url, $matches);
$domain = $matches[1];
preg_match("/^[a-zA-Z\s]+$/", $value);
preg_replace("/^[ ]+/u", '', $value)
preg_match("/^.{5,10}$/",$value);
mb_ereg("^.{5,10}$", $value);
mb_ereg("[ア-ン]",$value)
preg_match("/^#[a-fA-F0-9]{6}$",$value)
jQueryでやる手もあるけど、いい加減、PHPでもライブラリ化しておいた方がいいな?
あと、簡単に結果をチェックするならこのサイトで。 reg_match()による正規表現チェッカー