読者です 読者をやめる 読者になる 読者になる

NeverBlog::Likk::Unexistable;

見なかったことにして下さい

文字列どもをぶった切る

一昨日見つけた
Text::BreakIterator を使ってみました。
文字列を文字種ごとに分割するモジュールで

たとえば
"漢字とかカタカナがmixされた文字列etcを文字種ごとに1万回カットする"
のような文字列が有った場合このモジュールを使うと
"漢字,とか,カタカナ,が,mix,された,文字列,etc,を,文字種,ごとに,1,万回,カット,する"
という風にセパレータで区切ってくれる。
便利といえば便利なんだが、UTF-8Perlを組めばモジュールなしでも可能。

$cutting =~ s/([A-Za-z0-9])([^A-Za-z0-9])/$1,$2/g;#(\W)(\w)
$cutting =~ s/([^A-Za-z0-9])([A-Za-z0-9])/$1,$2/g;#(\w)(\W)じゃ上手く動作せず
$cutting =~ s/(\p{Hiragana}|\p{Katakana})(\p{Han})/$1,$2/g;
$cutting =~ s/(\p{Han})(\p{Hiragana}|\p{Katakana})/$1,$2/g;
$cutting =~ s/(\p{Hiragana})(\p{Katakana})/$1,$2/g;
$cutting =~ s/(\p{Katakana})(\p{Hiragana})/$1,$2/g;

こんな感じで多分大丈夫。
ただ、Text::BreakIteratorを使ってしまえば、
use Text::BreakIterator;
$sickle = Text::BreakIterator->new(jcode($strings)->euc);
my @list;
while (my $chunk = $sickle->next) { push @list, $chunk }
$cutting = jcode(join ',', @list)->utf8;

と見た目スッキリした感じになる。
試しに両方で10000回ループでTime::HiResによるベンチマークを計ってみた。

unicodeによる正規表現  → 初回 約3.4秒、二回目 約3.2秒 、三回目 約3.2秒
Text::BreakIterator を使用 → 初回 約8.3秒、二回目 約8.6秒 、三回目 約8.2秒

……Text::BreakIterator 遅ぇ…('A`)
まぁ、PerlがUTF8に対応される前に開発されたモジュールだし
仕方が無いといえば仕方が無いのか…

んで文字列の分割は、今回はココまで厳密に分ける必要は無い訳で、
送り仮名とかまで分割されてしまうのは少々やりにくい。

結局こんな感じで落ち着いた

$cutting =~ s/(\p{Hiragana}|\p{Katakana})(\p{Han}|[A-Za-z0-9_])/$1,$2/g;
$cutting =~ s/(\p{Hiragana})(\p{Katakana})/$1,$2/g;

この場合さっきの文字列は

"漢字や,カタカナが,mixされた,文字列etcを,文字種ごとに,1万回カットする"

とこんな感じに分割される
まぁ、"お惣菜"の場合"お,惣菜"になってしまうが良しとする。

さっそくローカルで試したスクリプトをアップしたら、
Perl が5.6のため上手く動かない…orz

Perl使いからのツッコミ大歓迎。