tests/auto/qtextstream/shift-jis.txt
author Alex Gilkes <alex.gilkes@nokia.com>
Mon, 11 Jan 2010 14:00:40 +0000
changeset 0 1918ee327afb
child 1 ae9c8dab0e3e
permissions -rw-r--r--
Revision: 200952
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
0
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
     1
Shift-JISテキストを正しく扱う
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
     2
最近の更新履歴
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
     3
2005-03-26: 「最初に」中、XML日本語プロファイル第2版に基づき、若干追記。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
     4
2005-03-09: 「最初に」中、文章を若干修正。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
     5
2003-06-24: Shift-JISの漢字を含むファイル名/パス名 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
     6
2003-05-31: 「最初に」中、「シフトJIS」などの表記について。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
     7
2003-05-24: CP932重複定義文字の変換 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
     8
2002-08-30: Perl 5.8.0 について。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
     9
2002-01-17: 長い文字列に対する正規表現検索 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    10
2001-12-15: ShiftJIS::Collate が overrideCJK パラメータを廃止したことに伴う 日本語文字列を並び替えるの書き換え。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    11
最初に 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    12
ありがちなエラー 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    13
エラーや間違いを防ぐ対策 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    14
文字列リテラルの作り方 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    15
正規表現とマッチ 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    16
グローバルマッチ 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    17
アルファベットの大文字と小文字 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    18
長い文字列に対する正規表現検索 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    19
外字の変換 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    20
CP932重複定義文字の変換 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    21
文字数を数える 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    22
文字単位に分割する 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    23
いろいろな分割 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    24
特定の長さで切りそろえる 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    25
日本語文字列を並び替える 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    26
Shift-JISの漢字を含むファイル名/パス名 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    27
最初に
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    28
日本語の文字コードにはいくつかのものが使われています。ある程度一般的なものなら、どれを使ってもよいでしょう(どの文字コードで符号化されているかの情報が失われさえしなければ)。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    29
例えば、日本語版Windowsでは、メモ帳でもDOS窓でもShift-JISが使われています。こういう場合、処理の途中でわざわざEUC-JPやUTF-8に変換するとしたら面倒です。デバッグのとき、「この段階ではこの変数には何が入っているのか」出力して点検するのはよく行われますが、このときEUC-JPとして収められていたら、作業は手間どるでしょう。入力も出力もShift-JISで行うつもりなら、処理の全体でShift-JISのまま扱えたらきっと便利でしょう。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    30
注: "シフトJIS", "Shift_JIS", "Shift-JIS" などの表記の違いについてはよくわかっていません。今のところ分かっていることは:
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    31
JIS X 0208:1997の附属書1(シフト符号化表現)には、「参考」として「この符号化表現は通常“シフトJISコード”と呼ばれている」の記述があります。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    32
IANA の CHARACTER SETS には、Shift_JIS と Windows-31J とが別に登録されています。また、Shift_JISについて、「CCS(符号化文字集合)はJIS X0201:1997とJIS X0208:1997であり、完全な定義はJIS X 0208:1997の附属書1に示されている。」と記しています。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    33
W3C の XML Japanese Profile には、Shift-JISにUnicodeへの変換表が複数ある旨の記載があります。XML Japanese Profile (Second Edition)では、Unicode Consortiumで公開されているMicrosoft CP932の変換表によるcharsetの名称 "x-sjis-cp932" を "Windows-31J" に変更しています。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    34
Microsoft社の Global Dev では、Codepage 932 を "Japanese Shift-JIS" と注記しています。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    35
しかし、Shift-JISにはある種の癖があって、ちょっとしたことがバグやエラーや文字化けの原因となります。なんとかならないものでしょうか。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    36
Perlは制御文字やナル文字を含むバイナリデータですら正しく処理できるように設計されているので、スクリプトやテキストをShift-JISで書いたくらいで問題になることはありません。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    37
しかし、perlがスクリプトを解釈するときは(通常)バイト単位で調べるので、Shift-JISのようなマルチバイト文字を含む符号はそのままでは直接理解できません。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    38
たとえば、Shift-JISで 'あ' という文字は、16進数で82 A0という2バイトで表されます。これを "\x82\xA0" と書いてもperlにとっては同じです。これが日本の(country)日本語の(language)文字であるとか、Shift-JISで書かれている(charset)とかいう情報はどこにも含まれていません。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    39
そのため、Shift-JISで書きたいときには、perlの誤解を受けないように書いてやらなければなりません。その配慮は、プログラマがしてやらなければなりません。この文書の記述は、そのような手間をかけても、Shift-JISを用いることに意義があると考えている人には参考になるかもしれません。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    40
そんな手間を掛けたくない人は、 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    41
Perl 5.8.x以降を使う。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    42
利点:perl5-porters@perl.org でサポートされている。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    43
欠点:独特の考え方があり、従来の日本語処理とは相容れないところがある(もっとも、そのうち慣れて気にならなくなるかもしれない)。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    44
jperlを使う。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    45
利点:Shift-JIS を文字として直接扱うことができる。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    46
欠点:現在、維持する人がいない。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    47
文字コードをUTF-8かEUC-JPに変換してから処理する。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    48
利点:Perl 5.8.x以降でなくても動作する変換用のモジュール(.pm)やライブラリ(.pl)がいろいろ入手可能。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    49
欠点:Shift-JISほど悪くないにしても、マルチバイト文字をシングルバイト文字と区別せず、ともに一文字として処理するのは面倒である。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    50
 という対処をとったほうがよいでしょう。これらのプログラムは有名なので、探せばすぐ見つかるでしょうから、入手先はここには示しません。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    51
なお、この文書に書かれている事が、最も勧められない方法なので、ここから先は、そのつもりでお読み下さい。この方法について何か疑問が生じたとしても、それについて他のところで質問すると、何でそんなやり方をしているのかと、きっと非難されるでしょう。かといって、私にも訊かないで下さい。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    52
Shift-JISを使ったときにありがちな(?)エラー
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    53
Shift-JISには、第2バイトが [@-~](ASCII 10進数で64-126)の範囲に入るものがあります。これらのASCII文字は、perlにとって特別な意味をもつことがあるため、しばしばエラーの原因となります。Shift-JISでは、2バイト文字の第2バイトは、[\x40-\x7E\x80-\xFC])の範囲にあるため、実に188分の63、約3分の1の文字が何らかの問題を起こし得るといえます。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    54
次に、Shift-JISを使ったときに起こりがちなエラーとその原因を示します。エラーメッセージはperlの違い(バージョンやどのプラットフォーム用のものであるか等)により多少の違いがあるかもしれません。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    55
エラーにならなくても、文字化けしたり、期待したような動作をしなかったりで、うまくいかないことがあります。この場合、エラーが出ない分、原因を自分で探さなければならなくなるためバグ取りはしばしば困難です。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    56
ここではエラーに対する対策は提示しません。対策はあとでまとめて書きます。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    57
なお、ここには文字コードをEUC-JPにしても起こるような問題やエラーは示しません。基本的に、EUC-JPなら起きないが、Shift-JISのときには起こるような事柄に限ります。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    58
エラーにはならないけど文字化けする(1) 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    59
例えば、"表示" とか "暴力" とかいうリテラルが文字化けを起こします。これらは "侮ヲ" とか "沫ヘ" になります。これは、"表" や "暴"の文字の第2バイトが \ であるため、ダブルクオート文字の中では次の文字のエスケープをすることになるので、表示 = 0x955C8EA6 であっても、クオートの結果は "表示" = 0x958EA6 となるからです。'表示' とすれば文字化けは起こりませんが、シングルクオートでも防げない文字化けやエラーがあります(次例)。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    60
エラーにはならないけど文字化けする(2) 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    61
例えば、"ミソ\500" というリテラルでは、\ が脱落してしまいます。これは、'ミソ\500' や q(ミソ\500) などとしても防ぐことができません。それは \\ という連続があると \ 1個になってしまうという規則があるからです。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    62
クオートやクオート風演算子の中では、文字列にクオートと同じ文字を含められるように、\ によるエスケープを付ければクオートの終端文字ではなく、文字列の一部とみなします。そのため、\\ が \ の文字を表すエスケープになります。これはクオートの始端・終端文字を何にしても同じことです。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    63
エラーにはならないけど文字化けする(3) 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    64
例えば、"丸十net" というリテラルが文字化けを起こします。これは "丸・
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    65
et" のように途中で改行されてしまいます。これは、"十" の第2バイトが \ であるため、ダブルクオート文字の中では次の 'n' と合わせて\nのすなわち改行文字を表すメタ文字として解釈されるからです。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    66
エラーにはならないけど文字化けする(4) 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    67
例えば、"引数 ARGV" というリテラルが文字化けを起こします。これは、" "(全角スペース)の第2バイトが @ であるため、ダブルクオート文字の中では次の ARGV と合わせて "@ARGV" という配列として変数展開を行うからです。@ARGVのように必ず定義されるような配列なら、展開されますが、別の場合ではエラーになるかもしれません(それは次項を参照)。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    68
In string, @dog now must be written as \@dog (Perl 5.6.0まで) 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    69
「文字列の中では、@dogは今は\@dogと書かなければならない」 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    70
前例でみたように、全角スペース " "の第2バイトは @ であるため、後ろの文字と合わせて配列であるかのように解釈しようとします。"犬 dog" のような場合、@dog という配列が定義されていればそれを用いて変数展開しますが、定義されていない場合、エラーメッセージを出します。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    71
``now must be written as''「今はこう書かなければならない」とは、Perl4までは配列の変数展開は行わなかったため、"hoge@foo.bar" のような書き方をすることができたのだが、今 Perlでは @foo が展開されてしまうので、注意を喚起するためエラーを出すようにしているようです(もしPerlが昔から配列の展開をサポートしていたら、エラーを出すことなく、黙って展開するだけだったかもしれません。次項も参照)。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    72
"犬 \dog" とすればいいという意見もありますが、\d がメタ文字として特別意味がないためにうまくいくのであって(Perl 5.6以降では、警告 Unrecognized escape \d passed through 「認識できないエスケープ \d が渡された」を引き起こします)、例えば "花 \flower" のときは、\f が改ページ文字として解釈され、文字化けします。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    73
Possible unintended interpolation of @dog in string (Perl 5.6.1以降) 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    74
文字列の中で、@dogが予期せずに展開される 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    75
前項と同じく、"犬 dog" ですが、Perl 5.6.1(ActivePerl 626)以降では、定義されていない配列でも黙って展開します。配列 @dog が展開されるので、"犬\x81" と同じになります。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    76
これはエラーではなく、警告になります。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    77
Can't find string terminator '"' anywhere before EOF 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    78
「終端文字 '"'がファイルの終り EOF までに見つからなかった」 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    79
例えば、"対応表" のようなリテラルでは、'表' の第2バイトが \ であるため、うしろの " をエスケープしてしまいます。このためperlは、その " はクオート文字列の終端文字とはみなさずに、文字列がさらに続くと考えてしまいます。これ以降、スクリプトの中に " の文字が全く含まれなければ、このようにエラー報告をします。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    80
qq{ "日本語" }のような場合にも注意しなければなりません。"本" の第二バイトは { なので、このままでは { }のネストがずれてしまい、同様のエラーが発生します。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    81
Bareword found where operator expected 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    82
「裸の語が演算子があってほしい位置に見つかった」 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    83
例えば、print "<img alt=\"対応表\" height=115 width=150>"; のような場合、\" による引用符のエスケープは、表 の第2バイトの\のため、\\ " という組み合わせになり、エスケープが打ち消されています。そのため、このリテラルは、perlから見ると、"<img alt=\"対応表\" で終わっています。そのため、リテラルの後に、height という「裸の語」(クオートで囲まれていない文字列)があるようにみて、ここには裸の語ではなく、演算子があるべきではないか?とperlは考えます。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    84
Unrecognized character \x82 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    85
「認識されない文字 \x82」 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    86
これは、非ASCII文字やその他の文字を「裸の語」にしたときに出るメッセージです。"対応表" のようなリテラルがあって、そのあとに "なんでもいいけど" のようなリテラルがあったとき、前例と同じ理由から起こるものです。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    87
また、q{マッチ} のような場合にも、'マ' の第二バイトが } なので、{ } のカッコはそこで終わってしまい、同様なエラーになります。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    88
マッチしないはずなのにマッチする(1) 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    89
"ヤカン" =~ /ポット/ はマッチします。それは、'ポ' の第二バイトが | なので、/ポット/ は /\x83|ット/ とみなされ、\x83 だけマッチすればよいからです。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    90
マッチしないはずなのにマッチする(2) 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    91
"兄弟" =~ /Z/ はマッチします。それは、'兄' の第二バイトが 'Z' だからです。第二バイトがアルファベットになる文字には注意が必要です。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    92
マッチするはずなのにマッチしない(1) 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    93
"運転免許" =~ /運転/ はマッチしません。それは、'運' の第二バイトが '^'なので、/運転/ は /\x89^転/ とみなされ、文字列の始め ^ の前に \x89 はないからです。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    94
Search pattern not terminated 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    95
「サーチパターンが終了しない」 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    96
これは、/表/ のように、第二バイトが \ である文字でサーチパターンを終わらせようとしたときに起こります。マッチ演算子の終端文字 / をエスケープしてしまうので、サーチパターンがさらに先に続くように解釈されます。その先にもう一度/はありますか? 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    97
あったところで、別のエラーが発生するでしょう。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    98
Substitution replacement not terminated 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
    99
「置換操作の置換文字列が終了しない」 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   100
置換演算子は s/PATTERN/REPLACEMENT/の形式をとらねばなりません。しかし s/表/裏/; のように、第二バイトが \ である文字でPATTERN部分を終わらせようとしたときにこのエラーが起こります。マッチ演算子の終端文字 / をエスケープしてしまうので、PATTERNがさらに先に続くように解釈されます。そのためperlは、PATTERNは 表/裏 の部分であると考え、3番目の/の先にREPLACEMENT部分があるに違いないと思うのですが、その先にもう一度/はありますか? 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   101
あったところで、別のエラーが発生するでしょう。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   102
unmatched [ ] in regexp 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   103
「正規表現にマッチしない [ ] がある」 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   104
例えば、/プール/ ではエラーが起こります。それは 'ー' の第二バイトが [ なので、/プール/ は /プ\x81[\x83\x8B/ とみなされ、perlは文字クラスがあるのではないかと思います。しかし文字クラスの終了を示す ] が見つからないのでエラーになります。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   105
エラーにはならないけど文字化けする(5) 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   106
例えば、lc('アイウエオ')は、'ヂツテトナ'を返します。Shift-JISの2バイト文字の中には、第2バイトがASCIIで英字に当たるものがあります。詳しくはアルファベットの大文字と小文字をご覧下さい。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   107
エラーや間違いを防ぐ対策
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   108
以上のようなエラーを防ぐにはさまざまな方法が考えられます。例えば、"表\示" と書けばいいなどという提案があります。もちろんそれでもかまいません。しかしそのためにはどの文字の後に \ を入れればいいかを知る必要があります。それは文字コード表を見れば一発で明らかです。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   109
…などという面倒なことが苦にならない人、文字コード表なんか(少なくとも問題になるような文字くらいは)暗記してしまえばいいというような人にとっては、確かにそれで解決になると思います。しかし、そのような人には、こんなページを見にくる必要もヒマもないでしょう。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   110
そこで、このようなページをわざわざ見にくるような人は、文字コード表をいちいち調べたくないひとだと仮定します。別にそうだからといって非難されることはありません。しかし、手間を惜しむあまり間違ったプログラムを平気で作っていては、顔にクリームパイをぶつけられても仕方ありません。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   111
文字列リテラルの作り方
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   112
よく知っておかねばならないことは、\ というエスケープ用の文字は、変数展開やメタ文字の解釈よりずっと前の段階でさまざまな影響を及ぼすということです。そのため、どうしたらデータを確実に変数の中に収められるかを考える必要があります。変数の内部に収めてしまえば、Perlがデータを適切に管理してくれます。よく知られている $str = "表示" の文字化けも、変数$strに代入する以前、ダブルクォートで囲んだ時点ですでに文字化けしていると考えるべきです。すでに文字化けしたデータを代入して、好い結果が得られるはずがありません。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   113
ヒアドキュメントは安全性の高い解決法です。ただし、終端文字列をシングルクォートで囲んでやらなくてはなりません。ダブルクォートで囲んだり、クォートを付けなかったりでは、予期せぬ変数展開やメタ文字の解釈を防ぐことができません。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   114
シングルクォートで終端文字列を囲んだヒアドキュメントでは、変数展開やメタ文字の解釈は何も起こりません。ただ、終端文字列(この場合は "\nEOF\n")を探すことだけを行います。ヒアドキュメントを使うと文字列に改行文字がつきますが、chompで除くといいでしょう。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   115
次の例は $str = 'ここにテキストを書く' と同じように働きますが、文字列の内容によって問題が起こりません。書いたとおりにリテラルを代入できると期待できます。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   116
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   117
chomp($str = << 'EOF');
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   118
ここにテキストを書く
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   119
EOF
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   120
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   121
$src = << 'EOF';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   122
  $path = "C:\\path\\file";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   123
  open FH, $path;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   124
EOF
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   125
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   126
多くの文字列を一度に作りたければ、splitで分割すると容易に作れます。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   127
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   128
($name, $career, $age, $memo) = split "\n", << 'EOF';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   129
田中一郎
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   130
プログラマ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   131
三十五
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   132
大福が好物である。  酒はあまり呑まない。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   133
EOF
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   134
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   135
もう少し簡潔に書きたければ、空白文字、\(2バイト文字に含まれているのは構わない)、およびカッコを含まないという条件で、qw() を使うことができます。例えば、@str = qw(表示 対応表 );のように空白を入れてカッコのエスケープを防ぎます。@str = qw(表示 対応表);のように空白を入れないとエラーの元です。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   136
1つの文字列を作る時でも、左辺を丸カッコで囲んでリストコンテキストを示すか、右辺をスライスにするかしなければなりません。これは、(現状では)qw// は split(' ', q//) の略記として実装しているからです。なお、Perl 5.6ではリストと等価になっているようです。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   137
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   138
($str) =  qw(百三十 );
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   139
 $str  = (qw/百三十 /)[0];
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   140
 $str  =  qw/百三十 /; # Perl 5.6
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   141
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   142
正規表現とマッチ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   143
正規表現のメタ文字は多いので、正規表現の中にShift-JISの文字列を埋めこむのは得策ではありません。例えば、/\Q対応表/ ではエラーになります。これは、/ / の範囲の決定が真っ先に行われ、その時点でエラーが発生するので、\Q の効果を及ぼすことができないからです。また、/\Q対応表\E/ は巧く行きません。これは、対応表\E という文字列を含むものにしかマッチしません。これは、\\ という連続があるため、\E が認識されないからでしょう(たぶん)。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   144
そのため、変数に入れて、マッチ演算子や置換演算子の中で展開させるとよろしいです。このとき日本語文字列は予めquotemeta 関数で処理しておきます。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   145
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   146
$pat = quotemeta +(qw/ 表 /)[0];
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   147
$str =~ /$pat\d+/; # 表1, 表2, ..などにマッチ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   148
  # しかし $str = '剣\\1' でもマッチする(この問題は後述)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   149
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   150
上のような書き方は確かに醜いですね。クオートの中で \Q \E を使う時は、正しい文字列が入っている変数と一緒になら問題が起こりません。こうすることで、\Q \E の範囲が明確になるからです。正しい文字列の作り方は、前述のリテラルの作りかたを参考にして下さい。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   151
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   152
$pat = "(?:\Q$str1\E|\Q$str2\E)*";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   153
$str =~ /$pat/;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   154
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   155
# 実は上の文は次の文と等価。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   156
# $pat = "(?:" . quotemeta($str1) . "|" . quotemeta($str2) . ")*";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   157
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   158
リテラルをクォートの中に直接埋めこむとうまく行かないことがあります。それは、perlが \E というメタ文字を発見しようというのを、Shift-JIS文字が妨げるためです。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   159
"\Q表\E"では、表Eにマッチする正規表現になります。表の第二バイトの \ と次の \が合わさるので、perlには\Q \x95 \\ Eの組み合わせであるように思われます。 \Qの作用の結果は\\x95\\x5cEになります。そのため、表Eにマッチします。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   160
"\Q表"はどうでしょう。この場合は、" " の範囲を決めるときに、表の第二バイトが後のクォートをエスケープしてしまうので、文字列の範囲が期待したようには定まらず、エラーになります。このエラーは\Qの効果を考慮する前に発生するので、防ぎようがありません。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   161
"\Q表\\E"はどうでしょう。確かにShift-JISでは問題ありません。しかし同じスクリプトをEUC-JPやUTF-8に変換したときには問題があります。表\Eと余分な2文字がある文字列でないとマッチしません。どちらにしろ、\をどこに添えるかを考える必要があるので、ここの趣旨に合いません。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   162
正規表現は例えば、次のようにします。もちろんこれはShift-JISのみに有効です。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   163
    $digit = '(?:[0-9]|\x82[\x4F-\x58])'; # 数字(半角と全角)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   164
    $upper = '(?:[A-Z]|\x82[\x60-\x79])'; # アルファベット大文字(半角と全角)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   165
    $lower = '(?:[a-z]|\x82[\x81-\x9A])'; # アルファベット小文字(半角と全角)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   166
    $space = '(?:[\ \n\r\t\f]|\x81\x40)'; # 空白文字(半角と全角)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   167
    $ascii = '[\x00-\x7F]';               # ASCII文字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   168
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   169
    # 全角平仮名(濁点・半濁点・踊り字を含む)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   170
    $hiraZ = '(?:\x82[\x9F-\xF1]|\x81[\x4A\x4B\x54\x55])'; 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   171
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   172
    # 全角片仮名(長音符・濁点・半濁点・踊り字を含む)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   173
    $kataZ = '(?:\x83[\x40-\x7E\x80-\x96]|\x81[\x5B\x4A\x4B\x52\x53])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   174
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   175
    # 半角片仮名(半角長音符・句読点を含む)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   176
    $kataH = '[\xA1-\xDF]';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   177
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   178
    $onebyte = '[\x00-\x7F\xA1-\xDF]';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   179
    $twobyte = '(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   180
    $char    = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   181
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   182
    # JIS文字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   183
    $all_JIS = '(?:[\x00-\x7f\xa1-\xdf]|'.
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   184
        . '\x81[\x40-\x7e\x80-\xac\xb8-\xbf\xc8-\xce\xda-\xe8\xf0-\xf7\xfc]|'
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   185
        . '\x82[\x4f-\x58\x60-\x79\x81-\x9a\x9f-\xf1]|'
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   186
        . '\x83[\x40-\x7e\x80-\x96\x9f-\xb6\xbf-\xd6]|'
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   187
        . '\x84[\x40-\x60\x70-\x7e\x80-\x91\x9f-\xbe]|'
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   188
        . '\x88[\x9f-\xfc]|\x98[\x40-\x72\x9f-\xfc]|\xea[\x40-\x7e\x80-\xa4]|'
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   189
        . '[\x89-\x97\x99-\x9f\xe0-\xe9][\x40-\x7e\x80-\xfc])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   190
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   191
    # ベンダ定義文字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   192
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   193
    # NEC特殊文字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   194
    $NEC_special = '(?:\x87[\x40-\x5d\x5f-\x75\x7e\x80-\x9c])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   195
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   196
    # NEC選定IBM拡張文字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   197
    $NEC_IBM_ext = '(?:\xed[\x40-\x7e\x80-\xfc]|\xee[\x40-\x7e\x80-\xec\xef-\xfc])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   198
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   199
    # IBM拡張文字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   200
    $IBM_ext     = '(?:[\xfa-\xfb][\x40-\x7e\x80-\xfc]|\xfc[\x40-\x4b])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   201
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   202
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   203
Shift-JISでマッチを行う時には、2つの問題があります。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   204
第二バイトがASCIIの領域に入る文字があるので、ASCIIを含むパターンにマッチする可能性がある。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   205
ある文字の第二バイトと次の文字の第一バイトが1文字であるかのようにマッチしてしまう。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   206
後者はEUC-JPでも起こりうる問題です(UTF-8なら起こらないが、今はそれが問題なのではない)。しかし前者はEUC-JPでは起こらないが、Shift-JISでは起こりうる問題です。これらを防ぐ方法は、結局同じことですが、正規表現の中に、常に先頭を含ませることです。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   207
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   208
# 先頭からマッチ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   209
$str =~ /^$char*?(?:$pat)/;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   210
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   211
末尾からのマッチではうまく行かないことがあります。"右" =~ /E$/を考えれば十分でしょう。また、"\x8E" x 30 . "E"は$str = "試試試試試試試試試試試試試試試E"であるが、"\x8E" x 31 . "E"は$str = "試試試試試試試試試試試試試試試殺"でありますから、Shift-JIS文字列を後ろから切り分ける適切な方法はないと考えられます。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   212
少なくとも、2バイト文字を構成しないバイト [\x00-\x3F\x7F] が見つかる所まで、極端な場合は文字列の最初までスキャンしないとわからず、しかも後読み lookbehind の正規表現 (?<=PATTERN)は今の所、不定長にできません((?<=(?:\A|[\x00-\x3F\x7F])$char*) とはできない)ので、先頭から文字単位でばらしてから処理するのが、結局は簡便なのかもしれません。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   213
グローバルマッチ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   214
グローバルマッチ /g の場合は、\Gを使いましょう。\Gは前回マッチした部分の末尾を指します。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   215
次の例では、置換されないのが望ましいのですが、\Gがないので、先頭から開始して文字列全体まで延びてマッチしなかったあと、改めて先頭から1バイト進んだ位置からスキャンを再開するので、ずれた位置なのにマッチしたと考えてしまいます。\Gを使わないと、間違った位置にマッチするかもしれないうえに、余計な再検査をするので、時間もかかります。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   216
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   217
    $str = '試試試試E試試試試E';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   218
    $pat = '殺';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   219
    $str =~ s/\G($char*?)($pat)/${1}E/og;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   220
    # '試試試試E試試試試E' のまま(正しい)。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   221
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   222
\Gを付けない場合
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   223
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   224
    $str = '試試試試E試試試試E';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   225
    $pat = '殺';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   226
    $str =~ s/($char*?)($pat)/${1}E/og; # '殺' があれば 'E' に置換
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   227
    print  $str;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   228
    # '試試試殺試試試殺' になってしまう(おかしい)。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   229
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   230
    試試試試E試試試試E
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   231
1回目 →→→→/→→→→/  (マッチしない)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   232
2回目 |→→→⇒|||||||||  (マッチしたので置換)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   233
3回目 |||||||||→→→→/  (マッチしない)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   234
4回目 ||||||||||→→→⇒  (マッチしたので置換)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   235
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   236
 凡例: → $charが2バイト文字にマッチ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   237
     / $charが1バイト文字にマッチ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   238
     ⇒ $patがマッチ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   239
     | スキャンの範囲外
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   240
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   241
ただし、パターンがゼロ文字幅にマッチする場合には、注意が必要です。次の例は、「ア」の前に 'Z' を入れるものです。第1例は文字のずれ('ア' : 0x8341に対して'泣A' : 0x8B8341がずれてマッチする)を防いでいません。第2例は、上の方法で「ずれ」を防ごうとしたのですが、Z への置換が連続して起こっています。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   242
これは第3例のようにする必要があります。これは、第2例では「なぜ?」に書いたように、置換されるからと考えられます。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   243
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   244
$str = "アイウエアアイウア泣A";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   245
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   246
print +($temp = $str) =~ s/(?=ア)/Z/g, $temp;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   247
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   248
print +($temp = $str) =~ s/\G($char*?)(?=ア)/${1}Z/g, $temp;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   249
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   250
print +($temp = $str) =~ s/\G(\A|$char+?)(?=ア)/${1}Z/g, $temp;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   251
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   252
結果 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   253
5    ZアイウエZアZアイウZア技ア
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   254
7    ZアイウエZZアZZアイウZZア泣A
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   255
4    ZアイウエZアZアイウZア泣A
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   256
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   257
なぜ? 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   258
     ア   イ   ウ   エ   ア   ア   イ   ウ   ア   泣   A
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   259
1  \G Z
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   260
2  \G$char$char$char$char Z
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   261
3                      \G Z
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   262
4                      \G$char Z
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   263
5      以下、省略
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   264
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   265
つまり、グローバルマッチでは、マッチがゼロ文字幅でないパターンの前には\G($char*?)を、ゼロ文字幅であるパターンの前には\G(\A|$char+?)を入れる必要があります。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   266
ただし、これでも正しく(?)マッチさせられない場合があります。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   267
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   268
$str = "0123000123";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   269
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   270
print +($temp = $str) =~ s/0*/Z/g, $temp;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   271
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   272
print +($temp = $str) =~ s/\G($char*?)0*/${1}Z/g, $temp;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   273
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   274
print +($temp = $str) =~ s/\G(\A|$char+?)0*/${1}Z/g, $temp;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   275
__END__
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   276
 9    ZZ1Z2Z3ZZ1Z2Z3Z
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   277
14    ZZ1ZZ2ZZ3ZZ1ZZ2ZZ3ZZ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   278
 7    Z1Z2Z3Z1Z2Z3Z
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   279
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   280
これは、パターンがゼロ文字幅にマッチするものであると、/gがその場で無限に足踏みして終了しなくなるのを防ぐため、perlは、マッチを強制的に進めているのですが(cf. perlre, Repeated patterns matching zero-length substring)、この進め方の真似(しかもバイト単位ではなく、文字単位で進むもの)が、\G($char*?)や\G(\A|$char+?)では、うまくできないからです。もっともこういうマッチをすることは、ほとんどないと考えられますので、気にする必要はないのかも知れません(<負け惜しみ)。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   281
アルファベットの大文字と小文字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   282
Shift-JISの2バイト文字の中には、第2バイトがASCIIで英字に当たるものがあります。そのため、関数 uc, lc や、メタ文字 \U, \Lが2バイト文字の一部を変換してしまったり(しかし関数 ucfirst, lcfirst や メタ文字 \u, \l は問題とならない)、m//i や s///iなどの /i修飾子によって違う文字なのにマッチしてしまったりすることがあります。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   283
Shift-JIS文字列に含まれるASCIIの英字を大文字または小文字に揃えたいなら、例えば、次のようなサブルーチンを作れば実現できます。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   284
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   285
$char = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   286
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   287
lc("PERLプログラミング");      # 'perlプロバラミンバ'
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   288
tolower("PERLプログラミング"); # 'perlプログラミング'
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   289
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   290
sub tolower {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   291
  my $str = $_[0];
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   292
  $str =~ s/\G($char*?)([A-Z]+)/$1\L$2/g;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   293
  $str;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   294
}
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   295
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   296
sub toupper {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   297
  my $str = $_[0];
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   298
  $str =~ s/\G($char*?)([a-z]+)/$1\U$2/g;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   299
  $str;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   300
}
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   301
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   302
ケース無視のマッチ /i の場合は、例えば 'エ'の第二バイトは 'G' であり、'ト'の第二バイトは 'g' であることから、'エ' =~ /ト/iはマッチします。ですから、Shift-JISで正確なマッチをしたければ、/i修飾子は使うことができません。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   303
かわりに、文字列に含まれるアルファベット(二バイト文字の第2バイトにあるものを除く)を小文字(または大文字、どちらか)に統一してマッチさせます。tolowerの定義は上をご覧下さい。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   304
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   305
$char = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   306
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   307
$lcstr = tolower($str);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   308
$lckey = tolower(quotemeta $key);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   309
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   310
if ($lcstr =~ /^$char*?$lckey/) {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   311
    print "matched";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   312
}
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   313
else {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   314
    print "not matched";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   315
}
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   316
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   317
または埋め込み修飾子 (?ismx-ismx) を用いても好い結果を得られます。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   318
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   319
"第1回Perl講縮のご案内" =~ /^$char*?PERL講習/i       # マッチする(困る)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   320
"第2回Perl講縮のご案内" =~ /^$char*?((?i)PERL)講習/  # マッチしない(良し)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   321
"第3回Perl講習のご案内" =~ /^$char*?((?i)PERL)講習/  # マッチする(良し)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   322
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   323
全角2バイトアルファベットのケース無視は、選択により実現できます(が、やっぱり変)。'A'の第2バイトが '`' なのも、ちょっと注意です(m`` などのとき致命的エラーになる。ただしバッククォートを使う意味は特にない)。原則的にはリテラルをマッチ演算子や置換演算子に直接埋め込むのは避けたい所です。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   324
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   325
/(?:P|p)(?:E|e)(?:R|r)(?:L|l)/;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   326
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   327
その代わりにこんなサブルーチンを作ってみてもよいかもしれません。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   328
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   329
$CharRE = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   330
 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   331
$pat = make_regexp_ignorecase("PERL講習");
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   332
print "第5回Perl講習会" =~ /^$char*?$pat/ ? "OK": "NOT";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   333
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   334
sub make_regexp_ignorecase {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   335
  my $str = $_[0];
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   336
  $str =~ s/\G([A-Za-z]+|$CharRE)/
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   337
    my $c = ord $1;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   338
    if($c == 0x82) {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   339
      my $v = vec($1,1,8);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   340
      0x81 <= $v && $v <= 0x9A ? sprintf('\\x82[\\x%2x\\x%2x]', $v, $v-33) :
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   341
      0x60 <= $v && $v <= 0x79 ? sprintf('\\x82[\\x%2x\\x%2x]', $v, $v+33) :
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   342
      quotemeta($1);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   343
    } 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   344
    elsif(0x41 <= $c && $c <= 0x5A || 0x61 <= $c && $c <= 0x7A) {"(?:(?i)$1)"}
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   345
    else {quotemeta($1)}
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   346
  /geo;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   347
  $str;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   348
}
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   349
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   350
長い文字列に対する正規表現検索
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   351
正規表現は、Perl にとって欠かせない存在といえます。しかし正規表現の制限として、*, +, {min,max} などの量指定子がマッチを繰り返せる回数の上限という問題があります。(詳細は perlre 参照のこと)。そのため、$char*? という正規表現には、危険性があります。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   352
例えば、次のようなマッチングを考えて見ましょう。$strは、「あ」が10万字連続したあとに、「アイABC」が連結された文字列です。このような文字列(ただし、「『あ』が10万字連続」ということは分からず、任意の Shift-JIS テキストであろうということにします)から、半角アルファベットが連続した部分を見つけたいとしましょう。すると、今までの考え方からすると、次のようにすればよいと思われます。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   353
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   354
my $char = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   355
my $str = ('あ' x 100000) . 'アイABC';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   356
$str =~ /^$char*?([A-Z]+)/o;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   357
print $1;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   358
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   359
しかし、これは、環境によっては、大きなエラーを引き起こします。例えば、Windows 98上で Active Perl 522 を用いた場合、Error: Runtime exception という Perl のエラーになりました。また、Windows 98上でVC++ 6.0でコンパイルされた Perl 5.6.1 だと、「このプログラムは不正な処理を行ったので強制終了されます。〜」などといったエラーになりました。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   360
このような問題をできるだけ防ぐためには、次のようにします。つまり、文字列の先頭から調べていく場合、二バイト文字の文字境界を間違えるのは、二バイト文字の第一バイトの直後を文字境界と誤認識した時だけです。Shift-JISでは、二バイト文字の第一バイトは、[\x81-\x9F\xE0-\xFC] だけです。あるいは、EUC-JP に変換可能な領域だけを考慮すれば、[\x81-\x9F\xE0-\xEF] だけということができます。それ以外のバイトの直後は、例えば、0x41 の直後は、'A' の直後か、'ア' の直後かは分かりませんが、確かに文字境界になります。従って、[\x81-\x9F\xE0-\xFC]+ (または [\x81-\x9F\xE0-\xEF]+ )のバイト(二バイト文字)が連続するところだけに注意すればよいことになります。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   361
このため、以下のように、^$char*? の代わりに $Apad を使い、\G$char*? の代わりに $Gpad を用いれば、一バイト文字か、二バイト文字のうち第二バイトが [\x40-\x7E\x80\xA0-\xDF] で終わるものが、少なくとも適当な間隔で(上限に達しないうちに)出現すれば、エラーにならずに処理することができます。(確率的な問題ですので、完全ではありません。)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   362
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   363
# 一回だけマッチ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   364
my $Apad  = '(?:(?:\A|[\x00-\x80\xA0-\xDF])(?:[\x81-\x9F\xE0-\xFC]{2})*?)';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   365
my $str1 = ('あ' x 100000) . 'アイABC';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   366
$str1 =~ /$Apad([A-Z]+)/o;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   367
print "$1\n"; # "ABC" と表示される。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   368
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   369
# グローバルマッチ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   370
my $Gpad  = '(?:(?:\G|[\x00-\x80\xA0-\xDF])(?:[\x81-\x9F\xE0-\xFC]{2})*?)';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   371
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   372
my $str2 = 'あ' x 100000 . 'アイABC'. 'お' x 100000 . 'XYZ';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   373
my @array = $str2 =~ /$Gpad([A-Z]+)/go;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   374
print "@array\n"; # "ABC XYZ" と表示される。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   375
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   376
外字の変換
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   377
ベンダ定義文字やユーザ定義文字を含む文字列を他の環境でも利用できるようにするには、適切な変換が必要です(無論、まったく同じ字体の利用はほとんど望めず、おそらくは類似した文字や文字列に変換することになるでしょう)。これはPerlでは置換演算子 s/// を使えば比較的容易に実現できます。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   378
あらかじめ、どの外字をどう変換するかを定義する変換テーブルを用意しなくてはなりません。これはPerlではハッシュにしておくとその後の処理が楽になります。ここでは、'w932_gai.txt'で定義する、Windows codepage-932コードに基づいた機種依存文字の(部分的)変換テーブルを使うことにします。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   379
次のコードでは、1文字づつマッチさせ、その文字が変換ハッシュのキーにあれば対応する値の文字列に置換し、そうでなければそのまま残します。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   380
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   381
require 'w932_gai.txt'; # %tableの定義(不完全!)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   382
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   383
$char = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   384
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   385
$str =~ s/($char)/exists $table{$1} ? $table{$1} : $1/geo;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   386
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   387
同様な処理は、つぎのような書き方でもできますが、外字にマッチする正規表現 $gaijiを用意する必要があります。ずれたマッチをしないために、こちらの正規表現には \G が必要です。例えば、$str = '∞@';の後ろ2バイトは "\x87\x40" ですが、こうすればマッチがずれる心配がありません。また、非欲張りマッチ ($char*?)を使えば $char が外字にマッチしないよう変更する必要はありません。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   388
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   389
require 'w932_gai.txt'; # %tableの定義(不完全!)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   390
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   391
$char  = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   392
$gaiji = '(?:[\x87][\x40-\x9c])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   393
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   394
$str =~ s/\G($char*?)($gaiji)/$1$table{$2}/g;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   395
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   396
CP932重複定義文字の変換
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   397
Microsoft Windows 日本語版で一般的に使用されているコードページ 932 (CP932) では、幾つかの文字が重複して定義された状態になっています。ここで、文字が重複定義されているとは、Unicodeの同じ符号位置に対応付けられていることとします。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   398
例えば、CP932 -> Unicode -> CP932 の順で変換されると、重複定義文字は、どれか一つに揃えられます。この優先順位は JIS X 0208, NEC特殊文字 (13区)、IBM拡張文字 (115〜119区)、NEC選定IBM拡張文字 (89〜92区) の順です。一例として、'∵' の場合、NEC特殊文字の "\x87\x9A" や IBM拡張文字の "\xFA\x5B" は、JIS X 0208 の "\x81\xE6" になります。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   399
しかし、CP-932 のテキスト中、重複定義文字がどれかに揃っていないことがあります。例えば "\x87\x9A" や "\xFA\x5B" が含まれていると、テキストを目で見ると違いがないのに、"\x81\xE6" で検索しても見つけられないことになります。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   400
重複定義文字を揃えるモジュールとして、ShiftJIS/CP932/Correct.pm があります。入手と使い方はPerlのページに戻れば見つかります。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   401
また、ShiftJIS/String.pm の strtr() または trclosure() を使う方法もあります。入手と使い方はPerlのページに戻れば見つかります。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   402
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   403
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   404
# (1) $necJIS -> $jisNEC (9対)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   405
   $necJIS = "\x87\x90\x87\x91\x87\x92\x87\x95\x87\x96\x87\x97\x87\x9A\x87\x9B\x87\x9C";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   406
      # NEC特殊文字のうち、JIS文字に変換されるべき非漢字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   407
   $jisNEC = "\x81\xE0\x81\xDF\x81\xE7\x81\xE3\x81\xDB\x81\xDA\x81\xE6\x81\xBF\x81\xBE";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   408
      # JIS文字のうち、NEC特殊文字に重複定義されている非漢字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   409
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   410
# (2) $necibmJIS -> $jisNECIBM (1対)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   411
   $necibmJIS = "\xEE\xF9";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   412
      # NEC選定IBM拡張文字のうち、JIS文字に変換されるべき非漢字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   413
   $jisNECIBM = "\x81\xCA";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   414
      # JIS文字のうち、NEC選定IBM拡張文字に重複定義されている非漢字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   415
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   416
# (3) $ibmJIS -> $jisIBM (2対)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   417
   $ibmJIS = "\xFA\x54\xFA\x5B";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   418
      # IBM拡張文字のうち、JIS文字に変換されるべき非漢字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   419
   $jisIBM = "\x81\xCA\x81\xE6";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   420
      # JIS文字のうち、IBM拡張文字に重複定義されている非漢字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   421
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   422
# (4) $ibmNEC -> $necIBM (13対)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   423
   $ibmNEC = "\xFA\x4A-\xFA\x53\xFA\x58\xFA\x59\xFA\x5A";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   424
      # IBM拡張文字のうち、NEC特殊文字に変換されるべき非漢字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   425
   $necIBM = "\x87\x54-\x87\x5D\x87\x8A\x87\x82\x87\x84";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   426
      # NEC特殊文字のうち、IBM拡張文字に重複定義されている非漢字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   427
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   428
# (5) $necibmIBM -> $ibmNECIBM (13対)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   429
   $necibmIBM = "\xEE\xEF-\xEE\xF8\xEE\xFA\xEE\xFB\xEE\xFC";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   430
      # NEC選定IBM拡張文字のうち、IBM拡張文字に変換されるべき非漢字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   431
   $ibmNECIBM = "\xFA\x40-\xFA\x49\xFA\x55\xFA\x56\xFA\x57";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   432
      # IBM拡張文字のうち、NEC選定IBM拡張文字に重複定義されている非漢字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   433
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   434
# (6) $necibmCJK -> $ibmCJK (360対)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   435
   $necibmCJK = "\xED\x40-\xEE\xEC";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   436
      # NEC選定IBM拡張文字中の漢字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   437
   $ibmCJK    = "\xFA\x5C-\xFC\x4B";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   438
      # IBM拡張文字中の漢字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   439
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   440
use ShiftJIS::String qw(trclosure);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   441
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   442
# 変換用クロージャの生成
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   443
$correctCP932 = trclosure(
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   444
    $necJIS.$necibmJIS.$ibmJIS.$ibmNEC.$necibmIBM.$necibmCJK, # from
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   445
    $jisNEC.$jisNECIBM.$jisIBM.$necIBM.$ibmNECIBM.$ibmCJK     # to
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   446
);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   447
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   448
$result = $correctCP932->($source); # $source を変換して $result を得る
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   449
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   450
文字数を数える
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   451
Shift-JIS文字列の文字数を数えるには、マッチ演算子を利用するならスカラーコンテキストで数えた方が若干速かったです。それより、置換演算子を利用したほうが速く書けるとわかりました。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   452
もっともXSで書いたほうがずっと速かったです。まあ、XSUBは無理に利用しなくてもよいでしょう。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   453
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   454
use Benchmark;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   455
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   456
$char = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   457
$s = "漢字あ\0AアCテスト -";
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   458
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   459
timethese (100000, {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   460
  le => q{
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   461
    ($str = $s) =~ s/$char/0/go;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   462
    $le = length $str;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   463
  },
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   464
  sg => q{
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   465
    $sg = ($str = $s) =~ s/$char//go;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   466
  },
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   467
  ab => q{
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   468
    $ab = 0;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   469
    $ab++ while $s =~ /[^\x81-\x9F\xE0-\xFC]|../g;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   470
  },
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   471
  ar => q{
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   472
    $ar = @{[ $s =~ /$char/go ]};
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   473
  },
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   474
  gr => q{
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   475
    $gr = grep defined, $s =~ /$char/go;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   476
  },
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   477
  wh => q{
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   478
    $wh = 0;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   479
    $wh++ while $s =~ /$char/go;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   480
  },
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   481
  sj => q{
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   482
    $sj = sjslen($s);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   483
  },
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   484
  xs => q{
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   485
    $xs = sjlength($s);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   486
  },
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   487
});
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   488
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   489
sub sjslen {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   490
  my($str,$len,$i,$c,$blen);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   491
  $str = shift;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   492
  $blen = length $str;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   493
  while ($i < $blen) {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   494
    $c = vec($str, $i, 8);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   495
    if (0x81 <= $c && $c <= 0x9F || 0xE0 <= $c && $c <= 0xFC){ $i++ }
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   496
    $i++,$len++;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   497
  }
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   498
  $len;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   499
}
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   500
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   501
結果 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   502
Benchmark: timing 100000 iterations of ab, ar, gr, le, sg, sj, wh, xs...
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   503
    ab:  4 wallclock secs ( 3.46 usr +  0.00 sys =  3.46 CPU) @ 28901.73/s
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   504
    ar:  6 wallclock secs ( 5.98 usr +  0.00 sys =  5.98 CPU) @ 16722.41/s
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   505
    gr:  6 wallclock secs ( 5.50 usr +  0.00 sys =  5.50 CPU) @ 18181.82/s
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   506
    le:  3 wallclock secs ( 2.09 usr +  0.00 sys =  2.09 CPU) @ 47846.89/s
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   507
    sg:  2 wallclock secs ( 1.92 usr +  0.00 sys =  1.92 CPU) @ 52083.33/s
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   508
    sj:  9 wallclock secs ( 8.57 usr +  0.00 sys =  8.57 CPU) @ 11668.61/s
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   509
    wh:  5 wallclock secs ( 4.78 usr +  0.00 sys =  4.78 CPU) @ 20920.50/s
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   510
    xs:  1 wallclock secs ( 0.38 usr +  0.00 sys =  0.38 CPU) @ 263157.89/s
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   511
        (warning: too few iterations for a reliable count)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   512
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   513
XSUB 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   514
int
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   515
sjlength(arg)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   516
    SV* arg
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   517
  PROTOTYPE: $
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   518
  PREINIT:
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   519
    unsigned char *str, *p, *e;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   520
    STRLEN byte, len = 0;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   521
  CODE:
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   522
    p = str = (unsigned char *)SvPV(arg, byte);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   523
    e = str + byte;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   524
    while (p < e) {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   525
        if (0x81 <= *p && *p <= 0x9F || 0xE0 <= *p && *p <= 0xFC)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   526
            ++p;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   527
        ++p, ++len;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   528
    }
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   529
    RETVAL = len;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   530
  OUTPUT:
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   531
    RETVAL
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   532
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   533
文字単位に分ける
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   534
Shift-JIS文字列を文字単位に分割しましょう。この場合は、XSを利用してもあまり速くなりませんでした。返り値のリストを用意するのに時間が取られるのか、やはりPerlの正規表現の処理はかなり速いものだということでしょう。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   535
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   536
use Benchmark;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   537
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   538
$char = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   539
$s = "日本語ニホンゴ\0ABC" x 100;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   540
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   541
timethese (1000, {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   542
   re => q{
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   543
      @re = $s =~ /$char/go;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   544
   },
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   545
   xs => q{
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   546
      @xs = sjsplit($s);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   547
   },
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   548
});
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   549
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   550
結果 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   551
Benchmark: timing 1000 iterations of re, xs...
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   552
    re:  7 wallclock secs ( 6.65 usr +  0.00 sys =  6.65 CPU) @ 150.38/s
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   553
    xs:  6 wallclock secs ( 5.33 usr +  0.00 sys =  5.33 CPU) @ 187.62/s
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   554
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   555
XSUB 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   556
void
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   557
sjsplit(arg)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   558
    SV* arg
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   559
  PROTOTYPE: $
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   560
  PREINIT:
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   561
    unsigned char *str, *p, *e;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   562
    STRLEN ch, byte, len = 0;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   563
  PPCODE:
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   564
    str = (unsigned char *)SvPV(arg,byte);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   565
    e = str + byte;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   566
    for (p = str; p < e; p++) {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   567
        if (0x81 <= *p && *p <= 0x9F || 0xE0 <= *p && *p <= 0xFC) ++p;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   568
        ++len;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   569
    }
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   570
    EXTEND(SP,len);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   571
    for (p = str; p < e; p += ch) {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   572
        ch = (0x81 <= *p && *p <= 0x9F || 0xE0 < *p && *p <= 0xFC) ? 2 : 1;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   573
        PUSHs(sv_2mortal(newSVpv(p,ch)));
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   574
    }
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   575
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   576
色々な分割
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   577
文字で分割でみたように、文字列を分割するには、m//gが便利です。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   578
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   579
$onebyte = '[\x00-\x7F\xA1-\xDF]';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   580
$twobyte = '(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   581
$char    = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   582
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   583
#1バイト文字の塊と2バイト文字の塊に分ける。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   584
   while ($str =~ /\G($onebyte*)($twobyte*)/g) {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   585
      push @one, $1 if $1 ne '';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   586
      push @two, $2 if $2 ne '';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   587
   }
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   588
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   589
#句点が最後の文字となるように分割する。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   590
# '。' ではいいが、文字によっては注意が必要。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   591
   @sentences = $str =~ /\G$char*?(?:。|.|$)/g; 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   592
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   593
特定の長さで切りそろえる
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   594
長い文字列を特定の長さ(バイト長)で切りそろえるなら、次のようにしてできます。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   595
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   596
$char = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   597
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   598
$str = 'わざわざEUC-JPに変換しないで、Shift-JISのまま処理'.
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   599
       'できたらいいんだけど、なかなか面倒だねえ。';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   600
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   601
print join "\n", bytebreak($str,15);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   602
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   603
sub bytebreak{
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   604
   my($byte,$bmax,$ch,@lines);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   605
   my $str = shift;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   606
   $byte = $bmax = shift;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   607
   foreach $ch ($str =~ /$char/go) {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   608
      $byte += length $ch;  # 次の文字を継ぎ足した長さ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   609
      if ($byte <= $bmax) {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   610
         $lines[-1] .= $ch; # 長すぎなければ継ぎ足す
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   611
      } else {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   612
         $byte = length $ch;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   613
         push @lines, $ch;  # さもなければ次の行へ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   614
      }
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   615
   }
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   616
   return @lines;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   617
  # 長さが足らない場合に、右をスペースで埋めたければ。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   618
  # return map {$_ .= ' ' x ($bmax - length)} @lines;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   619
}
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   620
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   621
禁則処理は、例えば次のようにして行います。単純な考え方では、禁則処理は、(i) 行頭禁則文字の直前で改行しない;(ii) 行末禁則文字の直後で改行しない;ということになります。また、"(a)"のように、行末禁則文字と行頭禁則文字の間に1文字しかない連続した部分は、その部分の全体が無改行になる点にも配慮します。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   622
この例では文字列の長さをバイト長 length で規定していますが、文字幅とバイト数は必ずしも比例しませんので、場合によっては(ギリシア文字は半角幅にしたいとか、またはプロポーショナルの場合とか、UTF-8の場合とか)文字幅を返す width のような関数を定義する必要があるでしょう。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   623
また、この例のやり方では、禁則による無改行部分だけで一行より長くなる場合は、はみだしを防げません。それが困るなら、禁則の例外として行を分ける(例えば$nextの長さが$bmaxを超えないようにする)処置が必要でしょう。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   624
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   625
$CharRE = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   626
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   627
# 行頭禁則文字(一部分)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   628
$NotAtBegin = q/)]}’”」』)]}!,.:;?、。々゛゜!,.:;?/;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   629
# 行末禁則文字(一部分)
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   630
$NotAtEnd   = q/([{‘“「『([{/;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   631
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   632
# ハッシュを作る
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   633
@NotAtBegin{$NotAtBegin =~ m/$CharRE/g} = ();
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   634
@NotAtEnd{  $NotAtEnd   =~ m/$CharRE/g} = ();
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   635
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   636
$Str = 'わざわざEUC-JPに変換しないで、Shift-JISのまま処理'.
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   637
       'できたらいいんだけど、なかなか面倒だねえ。';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   638
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   639
print join "\n", linebreak($Str,16);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   640
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   641
sub linebreak{
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   642
   my($byte,$i,@chars,$next,@lines);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   643
   my($str, $bmax, $pad) = @_;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   644
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   645
   # $byteは次の文字を継ぎ足したときの長さ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   646
   $byte = $bmax; # すぐ改行できるための初期値。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   647
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   648
   # 文字単位にばらす
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   649
   @chars = $str =~ /$CharRE/go; 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   650
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   651
   for ($i=0; $i<@chars; $i++) {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   652
      $next .= $chars[$i];         # 次の文字
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   653
      $byte += length $chars[$i];  # 次の文字を継ぎ足した長さ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   654
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   655
      # 次の文字が行末禁則のとき
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   656
      next if $i+1 < @chars && exists $NotAtEnd{ $chars[$i] };
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   657
      # 次の文字の次が行頭禁則のとき
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   658
      next if $i+1 < @chars && exists $NotAtBegin{ $chars[$i+1] };
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   659
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   660
      # 行の振り分け
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   661
     # 長すぎなければ継ぎ足す
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   662
      if ($byte <= $bmax) {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   663
         $lines[-1] .= $next;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   664
      }
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   665
     # さもなければ次の行へ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   666
      else {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   667
         push @lines, $next;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   668
         $byte = length $next;# 新しい行の長さ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   669
      }
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   670
      $next = '';
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   671
   }
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   672
   return defined $pad && 1 == length $pad # 詰め物
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   673
    ? map {$_ .= $pad x ($bmax - length)} @lines
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   674
    : @lines;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   675
}
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   676
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   677
ぶら下がり禁則の場合($bmin から $bmaxの範囲を許す)。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   678
      $bmin = $bmax - 2; # 例えば。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   679
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   680
      # 行の振り分け
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   681
     # 長すぎなければ継ぎ足す
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   682
      if ($byte <= $bmax && @lines && length $lines[-1] < $bmin){
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   683
         $lines[-1] .= $next;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   684
      }
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   685
     # さもなければ次の行へ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   686
      else {
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   687
         push @lines, $next;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   688
         $byte = length $next;# 新しい行の長さ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   689
      }
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   690
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   691
日本語文字列を並び替える
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   692
仮名文字列を五十音順にソートするモジュールとして、ShiftJIS/Collate.pm があります。入手と使い方はPerlのページに戻れば見つかります。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   693
「読み・表記照合」は次のようにして行います。sortYomiメソッドの受け取るリストの各要素は、[ 表記列, 読み列 ]という配列リファレンスでなければなりません。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   694
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   695
use ShiftJIS::Collate;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   696
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   697
my @data = (
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   698
  [qw/ 小山 こやま /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   699
  [qw/ 長田 ながた /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   700
  [qw/ 田中 たなか /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   701
  [qw/ 鈴木 すずき /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   702
  [qw/ 小嶋 こじま /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   703
  [qw/ 児島 こじま /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   704
  [qw/ 小山 おやま /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   705
  [qw/ 小島 こじま /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   706
  [qw/ 小島 こじま /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   707
  [qw/ 山田 やまだ /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   708
  [qw/ 永田 ながた /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   709
);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   710
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   711
@sort = ShiftJIS::Collate->new()->sortYomi(@data);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   712
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   713
「簡易代表読み照合」は次のようにして行います。sortDaihyoメソッドの受け取るリストの各要素は、[ 表記列, 読み列 ]という配列リファレンスでなければなりません。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   714
サンプルコード 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   715
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   716
#!perl
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   717
use ShiftJIS::Collate;
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   718
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   719
my @data = (
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   720
  [qw/ λ計算   らむだけいさん /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   721
  [qw/ JIS番号  じすばんごう   /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   722
  [qw/ 安達     あだち         /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   723
  [qw/ 安藤     あんどう       /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   724
  [qw/ 河西     かさい         /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   725
  [qw/ 河内     かわち         /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   726
  [qw/ 角田     かくた         /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   727
  [qw/ 角田     かどた         /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   728
  [qw/ 如月     きさらぎ       /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   729
  [qw/ 河内     こうち         /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   730
  [qw/ 幸山     こうやま       /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   731
  [qw/ 幸山     さきやま       /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   732
  [qw/ 佐藤     さとう         /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   733
  [qw/ 佐和田   さわだ         /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   734
  [qw/ 沢島     さわしま       /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   735
  [qw/ 沢田     さわだ         /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   736
  [qw/ 澤田     さわだ         /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   737
  [qw/ 角田     つのだ         /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   738
  [qw/ 槌井     つちい         /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   739
  [qw/ 土井     つちい         /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   740
  [qw/ 土居     つちい         /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   741
  [qw/ 戸井     とい           /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   742
  [qw/ 戸田     とだ           /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   743
  [qw/ 土井     どい           /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   744
  [qw/ 土居     どい           /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   745
  [qw/ 土岐     とき           /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   746
  [qw/ 安田     やすだ         /],
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   747
);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   748
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   749
@sort = ShiftJIS::Collate->new()->sortDaihyo(@data);
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   750
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   751
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   752
Shift-JISの漢字を含むファイル名/パス名
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   753
本項目は、他の項目に増して、検討不充分のまま記述していますので、もし何か参考にしようと思った場合、十分に注意の上、納得できるまでご自分の作業環境でテストしてください。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   754
Windows (95/98/NT/2000など) で、ファイル名やパス名が漢字(ここでは二バイト文字の意味で使っていますので、平仮名や記号なども含みます。)を含む場合、Perlで扱う際に問題が生じる可能性があります。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   755
末尾バイトが "\x5C" の漢字をもつファイル名/パス名
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   756
ディレクトリ操作関数(mkdir, rmdir, opendir, -d など)、ファイル操作関数(open, unlink, -f など)で、アクセスできないことがあります。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   757
ファイルの場合は、末尾に半角スペースを添えるとアクセスできる場合があります(例えば、-f '表 ' または -f "\x95\x5C\x20" など)。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   758
ディレクトリの場合は、末尾に / か \ を添えるとアクセスできる場合があります(例えば、-d '表/' または -d "\x95\x5C/" など)。末尾に添える文字を半角スペースとしても、うまくアクセスできる場合があります。添える文字の候補として、三種類の文字(スラッシュ、円記号、空白)を挙げましたが、どの文字がよいかは、関数によって異なる場合があるようです。使用する前に十分にテストしてください。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   759
なお、ディレクトリ名の末尾に / か \ を添える場合、もともと末尾に / か \ が付いている場合には、二重に付けるとうまく行かないおそれがありますので、文字列連結の前に検査したほうがよいでしょう。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   760
どうしても挙動が不明で信頼できない場合は、`` または qx// や system()関数などを通じてWindowsのコマンドを呼ぶのが良いと思います。
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   761
おまけ
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   762
 Shift-JIS で書かれた POD を Perl 5.8.1, 5.8.2 の Pod::Html で HTML に変換した場合、アンカーの名前は、 英数字と仮名文字 [0xA6..0xDF] を除き、 他の各バイトは下線('_')に変換されるようです。 具体的には、use locale; 下で、lc と s/\W/_/g を実行した結果 (cf. Pod::Html::anchorify) になります。 
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   763
[2003-11-18]
1918ee327afb Revision: 200952
Alex Gilkes <alex.gilkes@nokia.com>
parents:
diff changeset
   764
Perlのページ