忍者ブログ
natsuの秘密基地です
はまり
はまり一件ごとのお話の流れです
カレンダー
03 2024/04 05
S M T W T F S
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
プロフィール
HN:
natsu
性別:
男性
趣味:
酒など
自己紹介:
ここに書かれていることはフィクションです。
ブログ内検索
アクセス解析
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

UTF-8で何バイト目だぜ。
って言われたときに、
それが何文字目か調べるメソッドがNSStringにあれば、
便利な気がした。
あと、何行目か、とか。
 
ついでに問答無用のテキストロードも実装したい。
stringWithContentsOfFileじゃ、
標準のエンコードじゃないとロードしないみたい。
Shift JISの方言だったっけ。


 
レッツ、カテゴリ。



関数を3つ追加することにした。
- (int)getLineNumber:(int)numberOfChar;
- (int)getNumberOfCharUTF8:(int)countOfByte;
+ (NSString *)loadText:(NSString *)fileName;
この3つ。

getLineNumberと getNumberOfCharUTF8は
なんとなく昨日の感じでいいんだと思う。


なんでもロードはどうしよう。

 
だもんで、
stringWithContentsOfFile:usedEncoding:error
なんかね。いかにもいけそうな感じじゃん。
ということでトライ。
 
結果としていけた。
UTF-8とUTF-16だけ。
 
EUCとShift JISのMac弁はだめ。
エンコード指定ならOKみたい。
 
 
こうなったらあたってくだけろ法しかないのか。
 
 
もしかしたら、ファイルを開いたけど、どんなエンコードだったか。
っていうのが後で解ると便利かもしれない。
 
いま、自分がやってることは、
「テキストなら読む。ただそれだけだ」
っていう方針なので、必要ないけど。
 
今回NSStringの拡張をカテゴリでやってるんだけども、
カテゴリはメソッドの拡張しか出来ないので、
新たな値を保持したい場合、継承をするしか無い。
MyNSStringが出来ちゃう、と。
 
そういった意味で、チョッチ機能追加。
っていうときにカテゴリっていうのは便利な気がする。
プチ拡張。みたいな。
メソッド上書きはちと怖いけど。
javascript好きにはたまんない機能だと思うよ。
よくわかんないけど。
 
 
今回のケースでは、もし、
ロードしたテキストのエンコードがなんだったのかが知りたい場合、
それをオブジェクト内に保持しなきゃなんないので、
カテゴリではなく継承を行うことになる。
 
staticでリストを持つの?
動的辞書でNSStringのポインタをキーにすればいいけど。
 
 
まあ、素直が一番だから。
 
 
 
ソースは"何でもロード"が出来上がったらあぷります。
 
PR
UTF8。
マルチバイト文字ってねぇ。
難しいんですよ。
よくわかんないよ。わたしゃ。
 
 
鬼車にUTF8で渡していろいろ試したんだけども、
戻り値が案の定、何バイト目か。で、かえる。
 
そこまでの文字数を手に入れるにはどうすればいいんだろう。
UTF8は一個の文字を表現するためのバイト数が可変だ。
 
mblenでその文字何バイト?
を繰り返しやればいいのだろうか。
 
ええのんか。ええのんか。みたいな。(意味不明)
 
もう少し速そうな方法があればいいんだけども。
mblenが関数じゃなくてマクロだったらいいなあ。
とはおもった。
 
たぶん、こういうときにこそ、
関数呼び出しのオーバーヘッドを気にしなければいけない気がするから。
マクロだったらそのへんで繰り返し処理の効率がまだましになる。
それこそ、[lengthGetter length:str]
とかやっちゃうと大変なことになる気がする。
 
アセンブラで速くなんないかな、とか検討するにしてもね。
今それやっちゃうと、
iPhoneやiPadとか。柔軟性が無くなっちゃう。

それにマクロと同じくらいにしか速くならない気がする。
 
 
たぶんだけど、どの環境でもマクロが最も妥当。
勘だけど。
 
 
なんかGTKにそういう用途のコードがあるらしい。
ここでそのコードの引用を見つけた。
 
 
 
コードから察するに、
UTFの文字の先頭1byteと、
256の長さの配列で判定をするというものだと思う。
 
たぶんこういうことだと思う。
 
case1
その文字の1bit目が0の場合、
その1byteで一つの文字
 
case2
その文字の3bit目までが110の場合、
そのbyteと次のbyteの2byteで一つの文字
 
case3
その文字の4bit目までが1110の場合、
そのbyteと次の2つの3byteで一つの文字
 
case4
その文字の5bit目までが11110の場合、
そのbyteと次の3つの4byteで一つの文字
 
case5
その文字の6bit目までが111110の場合、
そのbyteと次の4つの5byteで一つの文字
 
case6
その文字の7bit目までが1111110の場合、
そのbyteと次の5つのbyteの6つで一つの文字
 
 
めんどい。要するに
 
0x000 <= 1byte目 <= 0x7F 1byte
0x80 <= 1byte目 <= 0xBF 得体の知れない何か
0xC0 <= 1byte目 <= 0xDF 2byte
0xE0 <= 1byte目 <= 0xEF 3byte
0xF0 <= 1byte目 <= 0xF7 4byte
0xF8 <= 1byte目 <= 0xFB 5byte
0xFC <= 1byte目 <= 0xFD 6byte
0xFEか0xFF == 1byte目 それらではない何か
 
ってことなので、
 
unsigned char charLength[256] = {
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 //ここまでで7F
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 //ここまででBF
 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
 //ここまででDF
 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
 //ここまででEF
 4,4,4,4,4,4,4,4,
 //ここまででF7
 5,5,5,5,
 //ここまででFB
 6,6,
 //ここまででFD
 1,1
 //FEとFF
};
 
って配列を使って、
文字のバイト数 = charLength[1byte目];
って感じで文字のバイト数が得られる。
 
で、ここまでくると、
gtkのコードにあるようにマクロが組めるようになる
えっとbyte型って、あったっけ、なかったっけ。
 
#define UTF8STEP(p) ((p) + charLength[*(unsigned char *)(p)])
 
pがchar *でそのまさに指し示している文字の先頭1バイトを
配列に渡して文字数を返してもらい、
それをpに足せば次の文字の先頭のアドレスになる。
これを検索ヒットの位置まで繰り返していけば、
そこまでの文字数が手に入ると。
 
 
 
 
適当に文字列を思いついて、
最後の方にヒットするように正規表現を書いて、
なんとなく何バイト目かを出して、
その何バイト目か、から何文字目かを出すのに計測。
 
って感じで計測をすればいいと思ったので、
このエントリーの下書きのファイルを読み込んで、
最後の方にヒットするように条件を書く。
改行があると頭おかしくなりそうなので、
あらかじめ取り除いておく。
 
mblen_l
2010-05-17 16:28:26.956 onitest[23352:903] Elapsed time: 0.000142
 
マクロ
2010-05-17 19:32:32.280 onitest[24805:903] Elapsed time: 0.000048
 
あー。やっぱマクロでやった方が速いっすねー。
ほら計測結果みてごらんなさい。
もう全然違う。

何回かやったけど、
大体2倍から2.5倍は確実に速い。

 
っていっても、
一回だけやるんだったら、どちらも問題にならないくらい速い。
どちらでもいいと思った。
 
 
前のはメイン文にずらずら書いたけど、クラスでまとめたら、
より、それっぽくなるような気がする。
なので、それっぽくする。
 
一つ、ソースファイルを作る。
二つ、クラスを作る。
三つ、オブジェクトを使うための変数を作る。
 
解りにくいけど、個数の話ね。
 
 
まずOnigiri.mを作る。
 
そこに、開始点と終了点を保持するデータ型と、
検索処理を行うクラスを作る。
 
検索処理に渡すパラメータは、
検索対象の文字列。
パターン。
結果の入るMutableArray。
Arrayは開始点と終了点を保持するデータ型が列をなす。
 
 
検索処理クラスからインスタンスを初めて作ったとき、
ライブラリをロードして、
ライブラリのインターフェイスのハンドルをもらっておく。
 
で、その検索処理クラスのインスタンスを使えば
文字列が検索できる。
 
インスタンスの最後の一つを解放したとき、
ライブラリが解放される。
 
って感じでよいんじゃないでしょうか。
 
 
実はdlopenやdlcloseは自前でカウンタを持っていて、
オープンするごとに+1、クローズするごとに-1、
しているらしい。
 
無理に自前で参照カウンタを持つ必要はないとおもう。
私は持ってるけど。

 
アプリ開始時に初期化、終了時に解放。
でももちろんいいし、
こっちの方が効率がいいと思う。
 
 
 
 
 
 
例のごとく、解凍されたディレクトリに、
libonig.2.dylib
libonig.a
oniguruma.h
を仕込んでみてください。
 
あと、結果だけども、
鬼車的にはendはマッチした文字列の
終端の次のindexをさすみたい。
 
 
 
私のonigiri::searchは、
文字列中で検索条件に引っかかったものは、
すべて洗い出したいんだけども、
正規表現によっては今の作りじゃそれができない。
ってこのへんはよくわかんないんだけど。
 
たとえば、
"zzzaffbdailfbafb"
"a.*?b"
だと
三つ引っかかりそうな気がするけど、
一つしか引っかからない。
 
 
ちなみに私は、do whileかなんかで回しゃいいんしょ。
ぐらいにしか思ってない。
 
 
ほかにもちょっと改造が必要。
日本語対応もしたい。
あと、シンタックスはrubyじゃなくてperlで。
 
 
んじゃあ、そんな感じに直しますか。
 


Copyright (C) 2010 NEST,
All right Resieved.*Powered by ニンジャブログ *Designed by にこるん  / 忍者ブログ / [PR]