=encoding euc-jp =head1 NAME =begin original perlfaq6 - Regular Expressions =end original perlfaq6 - 正規表現 =head1 DESCRIPTION =begin original This section is surprisingly small because the rest of the FAQ is littered with answers involving regular expressions. For example, decoding a URL and checking whether something is a number can be handled with regular expressions, but those answers are found elsewhere in this document (in L: "How do I decode or create those %-encodings on the web" and L: "How do I determine whether a scalar is a number/whole/integer/float", to be precise). =end original この章は驚くほど小さくなっています; なぜなら FAQ の残りの部分は正規表現を 伴った回答と一緒にあちこちに散在しているからです。 たとえば URL をデコードするとかあるものが数値かどうか確認することは 正規表現を使って処理されますが、この回答はこの資料のあらゆる所で 見つけることができます(正確には L: "How do I decode or create those %-encodings on the web" と L: "How do I determine whether a scalar is a number/whole/integer/float")。 =head2 How can I hope to use regular expressions without creating illegible and unmaintainable code? X X X X (判読し難い、保守できないようなものにすることなく正規表現を使うには?) =begin original Three techniques can make regular expressions maintainable and understandable. =end original 正規表現を保守可能なものにし、理解できるようにするための 三つの技法があります。 =over 4 =item Comments Outside the Regex (正規表現の外側にコメントを付ける) =begin original Describe what you're doing and how you're doing it, using normal Perl comments. =end original 通常のPerlのコメントを使って、 あなたが何を、どのようにしているかを説明します。 # turn the line into the first word, a colon, and the # number of characters on the rest of the line s/^(\w+)(.*)/ lc($1) . ":" . length($2) /meg; =item Comments Inside the Regex (正規表現の内側にコメントを付ける) =begin original The C modifier causes whitespace to be ignored in a regex pattern (except in a character class and a few other places), and also allows you to use normal comments there, too. As you can imagine, whitespace and comments help a lot. =end original /x 修飾子は、正規表現中にある空白を無視するようにし、 (文字クラスの中とその他いくつかにあるものを除く)、通常のコメントが使えるように します。 あなたの想像できるように、空白とコメントは非常に助けに なります。 =begin original C lets you turn this: =end original Cによって s{<(?:[^>'"]*|".*?"|'.*?')+>}{}gs; =begin original into this: =end original この正規表現を以下の様に記述できます: s{ < # opening angle bracket (?: # Non-backreffing grouping paren [^>'"] * # 0 or more things that are neither > nor ' nor " | # or else ".*?" # a section between double quotes (stingy match) | # or else '.*?' # a section between single quotes (stingy match) ) + # all occurring one or more times > # closing angle bracket }{}gsx; # replace with nothing, i.e. delete =begin original It's still not quite so clear as prose, but it is very useful for describing the meaning of each part of the pattern. =end original これでもまだ散文(prose)程には明確にはなっていませんが、 パターンの各部分の意味を説明するには非常に便利なものです。 =item Different Delimiters (異なった区切り) =begin original While we normally think of patterns as being delimited with C characters, they can be delimited by almost any character. L describes this. For example, the C above uses braces as delimiters. Selecting another delimiter can avoid quoting the delimiter within the pattern: =end original 私たちは通常、Cで区切られたものをパターンであると考えていますが、 パターンはほとんどすべてのキャラクタを使って区切ることが可能です。 Lはこれを説明しています。 たとえば、先に挙げたC では、区切りとしてカーリーブレースを使っています。 スラッシュ以外の区切りを選択することによって、パターンの中に存在する 区切り記号と同じものをクォートする手間を省くことができます。 s/\/usr\/local/\/usr\/share/g; # bad delimiter choice s#/usr/local#/usr/share#g; # better =begin original Using logically paired delimiters can be even more readable: =end original 論理的に組となる区切りはより読みやすいかもしれません: s{/usr/local/}{/usr/share}g; # better still =back =head2 I'm having trouble matching over more than one line. What's wrong? X X X (二行以上に対するマッチングでトラブルがありました。何が悪いのでしょう?) =begin original Either you don't have more than one line in the string you're looking at (probably), or else you aren't using the correct modifier(s) on your pattern (possibly). =end original マッチングの対象となっている文字列が実際には二行以上になっていないか、 パターンで正しい修飾子 (modifier)を使っていないかのいずれかでしょう (多分)。 =begin original There are many ways to get multiline data into a string. If you want it to happen automatically while reading input, you'll want to set $/ (probably to '' for paragraphs or C for the whole file) to allow you to read more than one line at a time. =end original 複数行のデータを一つの文字列にする方法はたくさんあります。 これを、入力を読み込んでいる間自動で行なわせたいというのであれば、 一度に二行以上読ませるために $/を(パラグラフ単位で読み込みたいなら '' を、 ファイル全体を読み込みたいなら C を)設定したくなるでしょう。 =begin original Read L to help you decide which of C and C (or both) you might want to use: C allows dot to include newline, and C allows caret and dollar to match next to a newline, not just at the end of the string. You do need to make sure that you've actually got a multiline string in there. =end original あなたが使いたいのは C か C のいずれなのか(あるいはこれら 両方なのか)を決めるのを助けるために、L を読んでください: C はドットが改行を含むようにしますし、C はキャレットとドル記号が 文字列の両端だけでなく改行の前後でマッチするようにします。 そして、複数行に渡る文字列を取得するようにさせる必要があります。 =begin original For example, this program detects duplicate words, even when they span line breaks (but not paragraph ones). For this example, we don't need C because we aren't using dot in a regular expression that we want to cross line boundaries. Neither do we need C because we don't want caret or dollar to match at any point inside the record next to newlines. But it's imperative that $/ be set to something other than the default, or else we won't actually ever have a multiline record read in. =end original たとえば、以下に挙げるプログラムは重複した単語を、たとえそれが行を またがっていても(ただしパラグラフはまたがっていない)探し出すものです。 この例では、Cの必要はありません; なぜなら、この行をまたがらせたい 正規表現でドットを使っていないからです。 Cを使う必要もありません; それは、キャレットやドル記号をレコードの中に ある改行の前後でマッチさせることは望んでいないからです。 しかし、$/ をデフォルト以外のものに設定することは避けられませんし、 そうしなければ複数行レコードを読み込むことはできないのです。 $/ = ''; # read in whole paragraph, not just one line while ( <> ) { while ( /\b([\w'-]+)(\s+\g1)+\b/gi ) { # word starts alpha print "Duplicate $1 at paragraph $.\n"; } } =begin original Here's some code that finds sentences that begin with "From " (which would be mangled by many mailers): =end original 以下の例は、“From ”で始まるセンテンス(多くのメイラーによって 変形されるであろうもの)を検索するものです。 $/ = ''; # read in whole paragraph, not just one line while ( <> ) { while ( /^From /gm ) { # /m makes ^ match next to \n print "leading from in paragraph $.\n"; } } =begin original Here's code that finds everything between START and END in a paragraph: =end original 次の例は、パラグラフ中の START と END に挟まれた部分を検索するものです: undef $/; # read in whole file, not just one line or paragraph while ( <> ) { while ( /START(.*?)END/sgm ) { # /s makes . cross line boundaries print "$1\n"; } } =head2 How can I pull out lines between two patterns that are themselves on different lines? X<..> (異なる行にある二つのパターンに挟まれている行を取り出すのはどうやればできますか?) =begin original You can use Perl's somewhat exotic C<..> operator (documented in L): =end original Perlの C<..> 演算子を使えます(L に説明があります)。 perl -ne 'print if /START/ .. /END/' file1 file2 ... =begin original If you wanted text and not lines, you would use =end original 行ではなく、テキストが必要なら次のようにします perl -0777 -ne 'print "$1\n" while /START(.*?)END/gs' file1 file2 ... =begin original But if you want nested occurrences of C through C, you'll run up against the problem described in the question in this section on matching balanced text. =end original しかし、C と C が現れるのを入れ子にさせたいというのであれば、 このセクションにある質問で説明されている問題に直面することになります。 =begin original Here's another example of using C<..>: =end original C<..>を使った別の例です: while (<>) { my $in_header = 1 .. /^$/; my $in_body = /^$/ .. eof; # now choose between them } continue { $. = 0 if eof; # fix $. } =head2 How do I match XML, HTML, or other nasty, ugly things with a regex? X X X X X X X (XML, HTML あるいはその他の扱いにくくて不細工なものを正規表現でマッチングさせるには?) =begin original Do not use regexes. Use a module and forget about the regular expressions. The L, L and L modules are good starts, although each namespace has other parsing modules specialized for certain tasks and different ways of doing it. Start at CPAN Search ( L ) and wonder at all the work people have done for you already! :) =end original 正規表現を使わないでください。 モジュールを使って、正規表現については忘れてください。 L, L, L モジュールが 良い開始点ですが、それぞれの名前空間には特定のタスクに専門化されていたり 違う方法で行ったりするその他のパースモジュールがあります。 CPAN Search ( L ) から始めて、あなたのために人々が すでに作業してくれていることに驚いてください! :) =head2 I put a regular expression into $/ but it didn't work. What's wrong? X<$/, regexes in> X<$INPUT_RECORD_SEPARATOR, regexes in> X<$RS, regexes in> ($/ に正規表現を入れたけど動きません。何が悪いの?) =begin original $/ has to be a string. You can use these examples if you really need to do this. =end original $/ は文字列でなければなりません。 もし本当にそうする必要があるなら、以下の例が使えます。 =begin original If you have L, this is easy. =end original もし L があれば、簡単です。 use File::Stream; my $stream = File::Stream->new( $filehandle, separator => qr/\s*,\s*/, ); print "$_\n" while <$stream>; =begin original If you don't have File::Stream, you have to do a little more work. =end original File::Stream がなければ、もう少し作業が必要です。 =begin original You can use the four-argument form of sysread to continually add to a buffer. After you add to the buffer, you check if you have a complete line (using your regular expression). =end original 継続的にバッファに追加するために、sysread の 4 引数形式が使えます。 バッファに追加した後、(正規表現を使って)行全体が揃っているかを チェックします。 local $_ = ""; while( sysread FH, $_, 8192, length ) { while( s/^((?s).*?)your_pattern// ) { my $record = $1; # do stuff here. } } =begin original You can do the same thing with foreach and a match using the c flag and the \G anchor, if you do not mind your entire file being in memory at the end. =end original もしファイル全体を最後までメモリに入れることを気にしないのなら、 foreach および、c フラグと \G アンカーを使ったマッチングを使って 同じことができます。 local $_ = ""; while( sysread FH, $_, 8192, length ) { foreach my $record ( m/\G((?s).*?)your_pattern/gc ) { # do stuff here. } substr( $_, 0, pos ) = "" if pos; } =head2 How do I substitute case-insensitively on the LHS while preserving case on the RHS? X X X X (演算子の左辺では大小文字を無視して、演算子の右辺では元の大小文字を保存しておくような置換をするには?) =begin original Here's a lovely Perlish solution by Larry Rosler. It exploits properties of bitwise xor on ASCII strings. =end original 以下に Larry Rosler によるとっても Perl ぽい解法があります。 これは ASCII 文字列に対するビット xor の動作を悪用します。 $_= "this is a TEsT case"; $old = 'test'; $new = 'success'; s{(\Q$old\E)} { uc $new | (uc $1 ^ $1) . (uc(substr $1, -1) ^ substr $1, -1) x (length($new) - length $1) }egi; print; =begin original And here it is as a subroutine, modeled after the above: =end original 以下はサブルーチンにしたものです; 上記と同じ手法です: sub preserve_case($$) { my ($old, $new) = @_; my $mask = uc $old ^ $old; uc $new | $mask . substr($mask, -1) x (length($new) - length($old)) } $string = "this is a TEsT case"; $string =~ s/(test)/preserve_case($1, "success")/egi; print "$string\n"; =begin original This prints: =end original これは以下のように表示します: this is a SUcCESS case =begin original As an alternative, to keep the case of the replacement word if it is longer than the original, you can use this code, by Jeff Pinyan: =end original 代替案として、もし元のものの方が長い場合には置き換え単語の大文字小文字を 維持する場合は、Jeff Pinyan による以下のコードが使えます: sub preserve_case { my ($from, $to) = @_; my ($lf, $lt) = map length, @_; if ($lt < $lf) { $from = substr $from, 0, $lt } else { $from .= substr $to, $lf } return uc $to | ($from ^ uc $from); } =begin original This changes the sentence to "this is a SUcCess case." =end original これは文章を "this is a SUcCess case." に変更します。 =begin original Just to show that C programmers can write C in any programming language, if you prefer a more C-like solution, the following script makes the substitution have the same case, letter by letter, as the original. (It also happens to run about 240% slower than the Perlish solution runs.) If the substitution has more characters than the string being substituted, the case of the last character is used for the rest of the substitution. =end original もしもっと C っぽい解決法が好みなら、 以下に挙げるスクリプトは、大小文字の違いを保ったまま、 文字毎に置換を行ないます。 (そしてこれは Perl っぽい解法より 240% 遅いです。) 置換対象の文字列よりも多くの文字が置換後の文字列にあるのであれば、 最後の文字の大小文字の種別が置換後の文字列の残りの部分の 文字に対して使われます。 # Original by Nathan Torkington, massaged by Jeffrey Friedl # sub preserve_case($$) { my ($old, $new) = @_; my $state = 0; # 0 = no change; 1 = lc; 2 = uc my ($i, $oldlen, $newlen, $c) = (0, length($old), length($new)); my $len = $oldlen < $newlen ? $oldlen : $newlen; for ($i = 0; $i < $len; $i++) { if ($c = substr($old, $i, 1), $c =~ /[\W\d_]/) { $state = 0; } elsif (lc $c eq $c) { substr($new, $i, 1) = lc(substr($new, $i, 1)); $state = 1; } else { substr($new, $i, 1) = uc(substr($new, $i, 1)); $state = 2; } } # finish up with any remaining new (for when new is longer than old) if ($newlen > $oldlen) { if ($state == 1) { substr($new, $oldlen) = lc(substr($new, $oldlen)); } elsif ($state == 2) { substr($new, $oldlen) = uc(substr($new, $oldlen)); } } return $new; } =head2 How can I make C<\w> match national character sets? X<\w> (C<\w> がローカルな文字セットにマッチするようにするには?) =begin original Put C in your script. The \w character class is taken from the current locale. =end original C をスクリプトに書いてください。 \w 文字クラスが現在のロケールから取られるようになります。 =begin original See L for details. =end original 詳しくは L を参照してください。 =head2 How can I match a locale-smart version of C? X (Cの locale-smart なバージョンでマッチさせるには?) =begin original You can use the POSIX character class syntax C documented in L. =end original L で記述されている、POSIX 文字クラス文法 C が 使えます。 =begin original No matter which locale you are in, the alphabetic characters are the characters in \w without the digits and the underscore. As a regex, that looks like C. Its complement, the non-alphabetics, is then everything in \W along with the digits and the underscore, or C. =end original あなたがどこにいるかに関わらず、英文字は \w から数字と下線を除いたものです。 正規表現としては、これは C のようになります。 その逆である非英字は、\W に含まれる全ての文字に数字と下線を加えたもの、 つまり C です。 =head2 How can I quote a variable to use in a regex? X X X (正規表現の中で使う変数をクォートするには?) =begin original The Perl parser will expand $variable and @variable references in regular expressions unless the delimiter is a single quote. Remember, too, that the right-hand side of a C substitution is considered a double-quoted string (see L for more details). Remember also that any regex special characters will be acted on unless you precede the substitution with \Q. Here's an example: =end original Perlの構文解析器(parser)は、区切りがシングルクォーテーションでない限り、 正規表現の中にある $variable や @variable といったものを展開します。 C による置換の右側にあるものはダブルクォーテーションで 括られた文字列とみなされるということを忘れないでください。 また、すべての正規表現演算子はその前に \Q を置いておかないと、 正規表現演算子として振る舞うということも忘れないでください。 以下に例を挙げます。 $string = "Placido P. Octopus"; $regex = "P."; $string =~ s/$regex/Polyp/; # $string is now "Polypacido P. Octopus" =begin original Because C<.> is special in regular expressions, and can match any single character, the regex C here has matched the in the original string. =end original C<.> 正規表現では特別で、任意の 1 文字にマッチングするので、 ここでの C は元の文字列の にマッチングします。 =begin original To escape the special meaning of C<.>, we use C<\Q>: =end original C<.> の特殊な意味をエスケープするには、C<\Q> を使います: $string = "Placido P. Octopus"; $regex = "P."; $string =~ s/\Q$regex/Polyp/; # $string is now "Placido Polyp Octopus" =begin original The use of C<\Q> causes the <.> in the regex to be treated as a regular character, so that C matches a C

followed by a dot. =end original C<\Q> を使うことによって、正規表現中の C<.> は通常の文字として扱われるので、 C は C

の後にピリオドがあるものにマッチングします。 =head2 What is C really for? X X (C は実際なんのためのものなのですか?) =begin original (contributed by brian d foy) =end original (brian d foy によって寄贈されました) =begin original The C option for regular expressions (documented in L and L) tells Perl to compile the regular expression only once. This is only useful when the pattern contains a variable. Perls 5.6 and later handle this automatically if the pattern does not change. =end original 正規表現の C オプション (L と L で文書化されています) は、正規表現を一度だけコンパイルするように Perl に伝えます。 これはパターンに変数が含まれている場合にのみ有用です。 Perls 5.6 以降では、パターンが変わらない場合はこれを自動的に扱います。 =begin original Since the match operator C, the substitution operator C, and the regular expression quoting operator C are double-quotish constructs, you can interpolate variables into the pattern. See the answer to "How can I quote a variable to use in a regex?" for more details. =end original マッチング演算子 C, 置換演算子 C, 正規表現クォート演算子 C はダブルクォート風構造なので、パターン中で変数を展開できます。 詳細については "How can I quote a variable to use in a regex?" の答えを 参照してください。 =begin original This example takes a regular expression from the argument list and prints the lines of input that match it: =end original この例は正規表現を引数リストから取って、それにマッチングする入力行を 表示します: my $pattern = shift @ARGV; while( <> ) { print if m/$pattern/; } =begin original Versions of Perl prior to 5.6 would recompile the regular expression for each iteration, even if C<$pattern> had not changed. The C would prevent this by telling Perl to compile the pattern the first time, then reuse that for subsequent iterations: =end original バージョン 5.6 より前の Perl では、C<$pattern> に変更がなくても反復毎に 正規表現が再コンパイルされます。 C をつけると、パターンを初回にコンパイルし、引き続く反復では 再利用するように Perl に伝えることで、再コンパイルを防ぎます: my $pattern = shift @ARGV; while( <> ) { print if m/$pattern/o; # useful for Perl < 5.6 } =begin original In versions 5.6 and later, Perl won't recompile the regular expression if the variable hasn't changed, so you probably don't need the C option. It doesn't hurt, but it doesn't help either. If you want any version of Perl to compile the regular expression only once even if the variable changes (thus, only using its initial value), you still need the C. =end original バージョン 5.6 以降では、変数が変更されていない場合は Perl は正規表現を 再コンパイルしませんので、おそらく C は不要です。 害はもたらしませんが、助けにもなりません。 どのバージョンでも、たとえ変数の値が変わっても正規表現を一度だけ コンパイルするようにしたい場合は、未だに C が必要です。 =begin original You can watch Perl's regular expression engine at work to verify for yourself if Perl is recompiling a regular expression. The C pragma (comes with Perl 5.005 and later) shows the details. With Perls before 5.6, you should see C reporting that its compiling the regular expression on each iteration. With Perl 5.6 or later, you should only see C report that for the first iteration. =end original Perl が正規表現を再コンパイルしたときに自分自身で検証するために、動作中の Perl の正規表現エンジンを見守ることもできます。 C プラグマ (Perl 5.005 以降で実装されています) は詳細を 表示します。 5.6 より前の Perl では、各反復で正規表現がコンパイルされる毎に C の 報告を見ることになります。 Perl 5.6 以降では、最初の反復でのみ C の報告を見ることになります。 use re 'debug'; my $regex = 'Perl'; foreach ( qw(Perl Java Ruby Python) ) { print STDERR "-" x 73, "\n"; print STDERR "Trying $_...\n"; print STDERR "\t$_ is good!\n" if m/$regex/; } =head2 How do I use a regular expression to strip C-style comments from a file? (ファイルから、C 形式のコメントを剥ぎ取る(strip)するにはどのように正規表現を使えば良いのでしょうか?) =begin original While this actually can be done, it's much harder than you'd think. For example, this one-liner =end original 実際これは可能なのですが、あなたが考えているよりも非常に難しいものです。 たとえば次の一行野郎 (one-liner) はほとんどの場合にうまく行きますが、 すべての場合ではありません。 perl -0777 -pe 's{/\*.*?\*/}{}gs' foo.c =begin original will work in many but not all cases. You see, it's too simple-minded for certain kinds of C programs, in particular, those with what appear to be comments in quoted strings. For that, you'd need something like this, created by Jeffrey Friedl and later modified by Fred Curtis. =end original そう、これは C のプログラムを簡単に考えすぎているのです。 特に、クォートされた文字列にコメントが出現するということを考慮していません。 このため、Jeffrey Friedl が作成し、後に Fred Curtis によって修正された 次の例のようなことが必要になります。 $/ = undef; $_ = <>; s#/\*[^*]*\*+([^/*][^*]*\*+)*/|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)#defined $2 ? $2 : ""#gse; print; =begin original This could, of course, be more legibly written with the C modifier, adding whitespace and comments. Here it is expanded, courtesy of Fred Curtis. =end original もちろんこれは、C 修飾子を使って空白やコメントを付加することで、 より読みやすくすることが可能です。 以下は Fred Curtis の提供による拡張版です。 s{ /\* ## Start of /* ... */ comment [^*]*\*+ ## Non-* followed by 1-or-more *'s ( [^/*][^*]*\*+ )* ## 0-or-more things which don't start with / ## but do end with '*' / ## End of /* ... */ comment | ## OR various things which aren't comments: ( " ## Start of " ... " string ( \\. ## Escaped char | ## OR [^"\\] ## Non "\ )* " ## End of " ... " string | ## OR ' ## Start of ' ... ' string ( \\. ## Escaped char | ## OR [^'\\] ## Non '\ )* ' ## End of ' ... ' string | ## OR . ## Anything other char [^/"'\\]* ## Chars which doesn't start a comment, string or escape ) }{defined $2 ? $2 : ""}gxse; =begin original A slight modification also removes C++ comments, possibly spanning multiple lines using a continuation character: =end original (継続文字を使って複数行にわたっていない限りは) 少しの変更で、おそらくは継続文字を使った複数行にわたるものも含む、 C++ コメントも除去します: s#/\*[^*]*\*+([^/*][^*]*\*+)*/|//([^\\]|[^\n][\n]?)*?\n|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)#defined $3 ? $3 : ""#gse; =head2 Can I use Perl regular expressions to match balanced text? X X X X X X X X X (Perl の正規表現をバランスされたテキストのマッチングに使えますか?) =begin original (contributed by brian d foy) =end original (brian d foy によって寄贈されました) =begin original Your first try should probably be the L module, which is in the Perl standard library since Perl 5.8. It has a variety of functions to deal with tricky text. The L module can also help by providing canned patterns you can use. =end original おそらく、まずはじめに試すべきなのは、Perl 5.8 から Perl 標準ライブラリに なっている L モジュールです。 これには扱いにくい文章を扱うための様々な関数があります。 L モジュールも、すぐ使えるパターンを提供することで 手助けしてくれます。 =begin original As of Perl 5.10, you can match balanced text with regular expressions using recursive patterns. Before Perl 5.10, you had to resort to various tricks such as using Perl code in C<(??{})> sequences. =end original Perl 5.10 以降では、再帰パターンを使って正規表現でバランスされた テキストをマッチングすることが出来ます。 Perl 5.10 以前では、C<(??{})> シーケンス内で Perl コードを使うといった さまざまな技を使う必要があります。 =begin original Here's an example using a recursive regular expression. The goal is to capture all of the text within angle brackets, including the text in nested angle brackets. This sample text has two "major" groups: a group with one level of nesting and a group with two levels of nesting. There are five total groups in angle brackets: =end original 以下は再帰的正規表現を使った例です。 ゴールは、(ネストしたものを含む)山かっこ内の全てのテキストを 捕らえることです。 サンプルの文章には二つの「主な」グループがあります: 1 レベルの ネストがあるものと、2 レベルのネストがあるものです。 これは全部で五つの山かっこグループがあります: I have some > and > > and that's it. =begin original The regular expression to match the balanced text uses two new (to Perl 5.10) regular expression features. These are covered in L and this example is a modified version of one in that documentation. =end original バランスされたテキストにマッチングする正規表現は二つの新しい (Perl 5.10 以降の)正規表現の機能を使います。 これらは L で説明されていて、この例はその文書にあるものの 修正版です。 =begin original First, adding the new possessive C<+> to any quantifier finds the longest match and does not backtrack. That's important since you want to handle any angle brackets through the recursion, not backtracking. The group C<< [^<>]++ >> finds one or more non-angle brackets without backtracking. =end original まず、絶対量指定子を追加することで、 最大マッチングを行って、バックトラックをしません。 これは、山かっこをバックトラッキングではなく再帰で扱いたいので 重要です。 グループ C<< [^<>]++ >> は、一つまたは複数の、山かっこでないものを バックトラッキングなしで探し出します。 =begin original Second, the new C<(?PARNO)> refers to the sub-pattern in the particular capture group given by C. In the following regex, the first capture group finds (and remembers) the balanced text, and you need that same pattern within the first buffer to get past the nested text. That's the recursive part. The C<(?1)> uses the pattern in the outer capture group as an independent part of the regex. =end original 次に、新しい C<(?PARNO)> は、C で与えられる特定の捕捉バッファ内の 副パターンを参照します。 以下の正規表現では、最初の捕捉バッファがバランスされたテキストを 発見し(さらに保存し)、ネストしたテキストを調べるために最初のバッファ内に 同じパターンを適用する必要があります。 これが再帰的な部分です。 C<(?1)> は、外側の捕捉バッファのパターンを正規表現内の 独立した部分として使います。 =begin original Putting it all together, you have: =end original これを全てまとめると: #!/usr/local/bin/perl5.10.0 my $string =<<"HERE"; I have some > and > > and that's it. HERE my @groups = $string =~ m/ ( # start of capture group 1 < # match an opening angle bracket (?: [^<>]++ # one or more non angle brackets, non backtracking | (?1) # found < or >, so recurse to capture group 1 )* > # match a closing angle bracket ) # end of capture group 1 /xg; $" = "\n\t"; print "Found:\n\t@groups\n"; =begin original The output shows that Perl found the two major groups: =end original Perl が二つの主なグループを発見したことが出力されます: Found: > > > =begin original With a little extra work, you can get the all of the groups in angle brackets even if they are in other angle brackets too. Each time you get a balanced match, remove its outer delimiter (that's the one you just matched so don't match it again) and add it to a queue of strings to process. Keep doing that until you get no matches: =end original もう少し作業すれば、たとえ他の山かっこがあっても、全ての山かっこの グループを得られます。 バランスされたマッチングが得られる毎に、外側のデリミタを取り除いて (これは今マッチングしたモノにまたマッチングしないようにするためです)、 処理する文字列のキューに追加します。 これを、マッチングしなくなるまで繰り返します: #!/usr/local/bin/perl5.10.0 my @queue =<<"HERE"; I have some > and > > and that's it. HERE my $regex = qr/ ( # start of bracket 1 < # match an opening angle bracket (?: [^<>]++ # one or more non angle brackets, non backtracking | (?1) # recurse to bracket 1 )* > # match a closing angle bracket ) # end of bracket 1 /x; $" = "\n\t"; while( @queue ) { my $string = shift @queue; my @groups = $string =~ m/$regex/g; print "Found:\n\t@groups\n\n" if @groups; unshift @queue, map { s/^$//; $_ } @groups; } =begin original The output shows all of the groups. The outermost matches show up first and the nested matches so up later: =end original 全てのグループが出力されます。 一番外側のマッチングが最初に表示され、ネストしたマッチングはその後に なります: Found: > > > Found: Found: > Found: =head2 What does it mean that regexes are greedy? How can I get around it? X X (正規表現が貪欲(greedy)であるとはどういうことですか?) =begin original Most people mean that greedy regexes match as much as they can. Technically speaking, it's actually the quantifiers (C, C<*>, C<+>, C<{}>) that are greedy rather than the whole pattern; Perl prefers local greed and immediate gratification to overall greed. To get non-greedy versions of the same quantifiers, use (C, C<*?>, C<+?>, C<{}?>). =end original ほとんどの人が、貪欲正規表現(greedy regexps)は可能な限りマッチすると 考えています。 技術的には、量指定子(C, C<*>, C<+>, C<{}>) はパターン全体よりも貪欲です; Perl は、全体的な貪欲性よりも局所貪欲性と即時の満足性を好みます。 同じ量指定子の non-greedy バージョンを得るには、 C, C<*?>, C<+?>, C<{}?>を使います。 =begin original An example: =end original 例: my $s1 = my $s2 = "I am very very cold"; $s1 =~ s/ve.*y //; # I am cold $s2 =~ s/ve.*?y //; # I am very cold =begin original Notice how the second substitution stopped matching as soon as it encountered "y ". The C<*?> quantifier effectively tells the regular expression engine to find a match as quickly as possible and pass control on to whatever is next in line, as you would if you were playing hot potato. =end original 二番目の置換が、“y ”を見つけてすぐにマッチングを中断していることに 注目してください。 量指定子 C<*?> は正規表現エンジンに対して、あなたが熱いジャガイモを 扱っているときのように、可能な限り早くマッチするものを見つけて制御を次の行に 渡すように効果的に指示します。 =head2 How do I process each word on each line? X (各行の単語単位に処理をするにはどうすれば良いですか?) =begin original Use the split function: =end original split 関数を使います: while (<>) { foreach my $word ( split ) { # do something with $word here } } =begin original Note that this isn't really a word in the English sense; it's just chunks of consecutive non-whitespace characters. =end original これは実際には英語でいうところの語ではないことに注意してください; これは、 単なる連続した空白でない文字の塊です。 =begin original To work with only alphanumeric sequences (including underscores), you might consider =end original アルファベットもしくは数字の並びのみを対象とするには以下のようにして できます。 while (<>) { foreach $word (m/(\w+)/g) { # do something with $word here } } =head2 How can I print out a word-frequency or line-frequency summary? (語の出現頻度や行の出現頻度のまとめを出力するには?) =begin original To do this, you have to parse out each word in the input stream. We'll pretend that by word you mean chunk of alphabetics, hyphens, or apostrophes, rather than the non-whitespace chunk idea of a word given in the previous question: =end original これを行うためには、入力ストリームにある単語のそれぞれについて解析する 必要があります。 私たちはここで、一つ前の質問と同様に、非空白文字の塊を語と するのではなく、英字、ハイフン、アポストロフィ、の塊を語とします: my (%seen); while (<>) { while ( /(\b[^\W_\d][\w'-]+\b)/g ) { # misses "`sheep'" $seen{$1}++; } } while ( my ($word, $count) = each %seen ) { print "$count $word\n"; } =begin original If you wanted to do the same thing for lines, you wouldn't need a regular expression: =end original 同じことを行に対して行いたいのであれば、正規表現は必要ないでしょう。 my (%seen); while (<>) { $seen{$_}++; } while ( my ($line, $count) = each %seen ) { print "$count $line"; } =begin original If you want these output in a sorted order, see L: "How do I sort a hash (optionally by value instead of key)?". =end original ソートされた順序で出力したいのなら、L: "How do I sort a hash (optionally by value instead of key)?" を参照してください。 =head2 How can I do approximate matching? X X (曖昧なマッチング (approximate matching) はどうやればできますか?) =begin original See the module L available from CPAN. =end original CPAN で入手できる L モジュールを参照してください。 =head2 How do I efficiently match many regular expressions at once? X X X (たくさんの正規表現を一度に効率良くマッチングするには?) =begin original (contributed by brian d foy) =end original (brian d foy によって寄贈されました) =begin original If you have Perl 5.10 or later, this is almost trivial. You just smart match against an array of regular expression objects: =end original Perl 5.10 以降では、これはほぼささいな問題です。 単に正規表現オブジェクトの配列に対してスマートマッチングします: my @patterns = ( qr/Fr.d/, qr/B.rn.y/, qr/W.lm./ ); if( $string ~~ @patterns ) { ... }; =begin original The smart match stops when it finds a match, so it doesn't have to try every expression. =end original マッチングするとスマートマッチングは停止するので、全ての正規表現を 試す必要はありません。 =begin original Earlier than Perl 5.10, you have a bit of work to do. You want to avoid compiling a regular expression every time you want to match it. In this example, perl must recompile the regular expression for every iteration of the C loop since it has no way to know what C<$pattern> will be: =end original Perl 5.10 より前では、少し作業が必要です。 マッチングを行う毎に Perl が正規表現をコンパイルすることを避けてください。 この例の場合、C<$pattern> が何者なのかを知る方法がないので、perl は C ループの反復毎に正規表現を再コンパイルしなければなりません: my @patterns = qw( foo bar baz ); LINE: while( ) { foreach $pattern ( @patterns ) { if( /\b$pattern\b/i ) { print; next LINE; } } } =begin original The C operator showed up in perl 5.005. It compiles a regular expression, but doesn't apply it. When you use the pre-compiled version of the regex, perl does less work. In this example, I inserted a C to turn each pattern into its pre-compiled form. The rest of the script is the same, but faster: =end original C 演算子は perl 5.005 で現れました。 これは正規表現をコンパイルしますが、適用はしません。 プリコンパイルされた正規表現を使うと、perl の作業は減ります。 この例では、各パターンをプリコンパイルされた形式に変換するための C を挿入しています。 スクリプトの残りの部分は同じですが、より速いです: my @patterns = map { qr/\b$_\b/i } qw( foo bar baz ); LINE: while( <> ) { foreach $pattern ( @patterns ) { if( /$pattern/ ) { print; next LINE; } } } =begin original In some cases, you may be able to make several patterns into a single regular expression. Beware of situations that require backtracking though. =end original いくつかの場合では、複数のパターンを一つの正規表現にできるかもしれません。 しかし、バックトラッキングが必要になる状況に注意してください。 my $regex = join '|', qw( foo bar baz ); LINE: while( <> ) { print if /\b(?:$regex)\b/i; } =begin original For more details on regular expression efficiency, see I by Jeffrey Friedl. He explains how the regular expressions engine works and why some patterns are surprisingly inefficient. Once you understand how perl applies regular expressions, you can tune them for individual situations. =end original 正規表現の効率に関するさらなる詳細については、Jeffrey Friedl による I を参照してください。 彼は、どのように正規表現エンジンが動作するかと、なぜある種のパターンが 驚くほど非効率かについて説明しています。 perl がどのように正規表現を適用するかを理解すれば、これらを個々の状況に 調整できます。 =head2 Why don't word-boundary searches with C<\b> work for me? X<\b> (なぜ C<\b> を使った単語境界の検索がうまく行かないのでしょうか?) =begin original (contributed by brian d foy) =end original (brian d foy によって寄贈されました) =begin original Ensure that you know what \b really does: it's the boundary between a word character, \w, and something that isn't a word character. That thing that isn't a word character might be \W, but it can also be the start or end of the string. =end original 実際に \b が何を行うかをしっかり理解してください: これは単語文字 (\w) と、単語文字でない何かとの境界です。 単語文字でないというのは \W かもしれませんが、文字列の最初と最後にも あります。 =begin original It's not (not!) the boundary between whitespace and non-whitespace, and it's not the stuff between words we use to create sentences. =end original これは空白と非空白との境界ではなく(違うんです!)、私たちが文を作るのに 使う単語の間のものではありません。 =begin original In regex speak, a word boundary (\b) is a "zero width assertion", meaning that it doesn't represent a character in the string, but a condition at a certain position. =end original 正規表現的に言うと、単語境界は (\b) は「ゼロ幅アサーション」です; これは文字列中の文字ではなく、ある位置での条件を表現しています。 =begin original For the regular expression, /\bPerl\b/, there has to be a word boundary before the "P" and after the "l". As long as something other than a word character precedes the "P" and succeeds the "l", the pattern will match. These strings match /\bPerl\b/. =end original 正規表現 /\bPerl\b/ では、"P" の前と "l" の後に単語境界がなければなりません。 "P" の前と "l" の後に単語文字以外の何かがある限り、このパターンは マッチングします。 以下の文字列は /\bPerl\b/ にマッチングします。 "Perl" # no word char before P or after l "Perl " # same as previous (space is not a word char) "'Perl'" # the ' char is not a word char "Perl's" # no word char before P, non-word char after "l" =begin original These strings do not match /\bPerl\b/. =end original これらの文字列は /\bPerl\b/ にマッチングしません。 "Perl_" # _ is a word char! "Perler" # no word char before P, but one after l =begin original You don't have to use \b to match words though. You can look for non-word characters surrounded by word characters. These strings match the pattern /\b'\b/. =end original しかし、単語にマッチングさせるために \b を使う必要はありません。 単語文字に囲まれた非単語文字を探すのに使えます。 これらの文字列は、パターン /\b'\b/ にマッチングします。 "don't" # the ' char is surrounded by "n" and "t" "qep'a'" # the ' char is surrounded by "p" and "a" =begin original These strings do not match /\b'\b/. =end original これらの文字列は /\b'\b/ にマッチングしません。 "foo'" # there is no word char after non-word ' =begin original You can also use the complement of \b, \B, to specify that there should not be a word boundary. =end original 単語境界ではないということを指定するために、\b の逆である \B も使えます。 =begin original In the pattern /\Bam\B/, there must be a word character before the "a" and after the "m". These patterns match /\Bam\B/: =end original パターン /\Bam\B/ では、"a" の前と "m" の後ろに単語文字が必要です。 これらはパターン /\Bam\B/ にマッチングします: "llama" # "am" surrounded by word chars "Samuel" # same =begin original These strings do not match /\Bam\B/ =end original これらの文字列は /\Bam\B/ にマッチングしません。 "Sam" # no word boundary before "a", but one after "m" "I am Sam" # "am" surrounded by non-word chars =head2 Why does using $&, $`, or $' slow my program down? X<$MATCH> X<$&> X<$POSTMATCH> X<$'> X<$PREMATCH> X<$`> (なぜ $&, $`, $' を使うとプログラムが遅くなるの?) =begin original (contributed by Anno Siegel) =end original (Anno Siegel によって寄贈されました) =begin original Once Perl sees that you need one of these variables anywhere in the program, it provides them on each and every pattern match. That means that on every pattern match the entire string will be copied, part of it to $`, part to $&, and part to $'. Thus the penalty is most severe with long strings and patterns that match often. Avoid $&, $', and $` if you can, but if you can't, once you've used them at all, use them at will because you've already paid the price. Remember that some algorithms really appreciate them. As of the 5.005 release, the $& variable is no longer "expensive" the way the other two are. =end original プログラムのどこかでそういった変数が使われているのを見つけてしまうと、 Perl はすべてのパターンマッチングに対してそれに対処することを やらなければなりません。 これは、全てのパターンマッチングに置いて、一部は $` に、一部は $& に、 一部は $' に、という形で文字列全体がコピーされるということを意味します。 従って、ペナルティは長い文字列とパターンを何度もマッチングさせるときに 最も厳しいものとなります。 可能であれば $& や $'、$` を使わないようにすべきなのですが、 それができないのであれば、一度これらの変数を使ってしまったら好きなように 使いましょう; なぜなら、罰金はすでに払ってしまったのですから。 アルゴリズムの中にはこういった変数を使うことが適切であるものが あるということに注意してください。 リリース 5.005 からは、$& はもはや「高価な」ものではありません。 =begin original Since Perl 5.6.1 the special variables @- and @+ can functionally replace $`, $& and $'. These arrays contain pointers to the beginning and end of each match (see perlvar for the full story), so they give you essentially the same information, but without the risk of excessive string copying. =end original Perl 5.6.1 から、特殊変数 @- と @+ で $`, $&, $' の機能を 置き換えられるようになりました。 これらの配列はそれぞれのマッチングの開始位置と終了位置へのポインタを 含みます(詳しい話については perlvar を参照してください)ので、 本質的にはこれらから同じ情報が得られますが、 過度の文字列コピーのリスクはありません。 =begin original Perl 5.10 added three specials, C<${^MATCH}>, C<${^PREMATCH}>, and C<${^POSTMATCH}> to do the same job but without the global performance penalty. Perl 5.10 only sets these variables if you compile or execute the regular expression with the C

modifier. =end original Perl 5.10 では、グローバルなペナルティなしに同じ作業をするための 3 つの特殊変数 C<${^MATCH}>, C<${^PREMATCH}>, C<${^POSTMATCH}> が 追加されました。 Perl 5.10 では、正規表現を C

修飾子付きでコンパイルしたり 実行したりした場合にのみこれらの変数がセットされます。 =head2 What good is C<\G> in a regular expression? X<\G> (正規表現の中で C<\G> を使うと何が良いのですか?) =begin original You use the C<\G> anchor to start the next match on the same string where the last match left off. The regular expression engine cannot skip over any characters to find the next match with this anchor, so C<\G> is similar to the beginning of string anchor, C<^>. The C<\G> anchor is typically used with the C flag. It uses the value of C as the position to start the next match. As the match operator makes successive matches, it updates C with the position of the next character past the last match (or the first character of the next match, depending on how you like to look at it). Each string has its own C value. =end original 次のマッチングを同じ文字列のうち、前回のマッチングを中止したところから 始めるために C<\G> アンカーを使います。 正規表現エンジンはこのアンカーがあるときには次のマッチングを探すために 何の文字も読み飛ばさないので、C<\G> は文字列先頭アンカーである C<^> と 似ています。 C<\G> アンカーは典型的には C フラグと共に使います。 これは次のマッチングの開始位置として C の値を使います。 マッチング演算子がマッチングに成功すると、C の値を最後のマッチングの 次の文字(または次のマッチングの最初の文字; これはあなたがこれをどのように 見るかの問題です)の位置に更新します。 各文字列はそれぞれ独自の C の値を持ちます。 =begin original Suppose you want to match all of consecutive pairs of digits in a string like "1122a44" and stop matching when you encounter non-digits. You want to match C<11> and C<22> but the letter shows up between C<22> and C<44> and you want to stop at C. Simply matching pairs of digits skips over the C and still matches C<44>. =end original "1122a44" のような文字列で、連続した数字のペアの全てにマッチングし、数字で ないものが現れたら停止したいとします。 C<11> と C<22> にはマッチングしたいですが、C<22> と C<44> の間に C が 現れると、C で停止したいとします。 数字のペアのマッチングは単に C を読み飛ばし、引き続き C<44> に マッチングします。 $_ = "1122a44"; my @pairs = m/(\d\d)/g; # qw( 11 22 44 ) =begin original If you use the C<\G> anchor, you force the match after C<22> to start with the C. The regular expression cannot match there since it does not find a digit, so the next match fails and the match operator returns the pairs it already found. =end original C<\G> アンカーを使うと、C<22> の後のマッチングを C から始めることを 強制します。 ここでは数字が見付からないのでマッチングできず、従って次のマッチングは 失敗してマッチング演算子は既に見付かったペアを返します。 $_ = "1122a44"; my @pairs = m/\G(\d\d)/g; # qw( 11 22 ) =begin original You can also use the C<\G> anchor in scalar context. You still need the C flag. =end original スカラコンテキストにも C<\G> アンカーが使えます。 C フラグはまだ必要です。 $_ = "1122a44"; while( m/\G(\d\d)/g ) { print "Found $1\n"; } =begin original After the match fails at the letter C, perl resets C and the next match on the same string starts at the beginning. =end original 文字 C のマッチングに失敗した後、perl は C をリセットし、 同じ文字列に対する次のマッチングは先頭から行います。 $_ = "1122a44"; while( m/\G(\d\d)/g ) { print "Found $1\n"; } print "Found $1 after while" if m/(\d\d)/g; # finds "11" =begin original You can disable C resets on fail with the C flag, documented in L and L. Subsequent matches start where the last successful match ended (the value of C) even if a match on the same string has failed in the meantime. In this case, the match after the C loop starts at the C (where the last match stopped), and since it does not use any anchor it can skip over the C to find C<44>. =end original L と L に書いているように、C フラグをつけることで C のリセットを抑制できます。 引き続くマッチングは、その間に同じ文字列でのマッチングが失敗していても、 直前の成功したマッチングが終了した場所 (C の値) から開始されます。 この場合、C ループの後のマッチングは (最後のマッチングが停止した) C から開始され、何のアンカーも使っていないので、C<44> を見つけるために C をスキップできます。 $_ = "1122a44"; while( m/\G(\d\d)/gc ) { print "Found $1\n"; } print "Found $1 after while" if m/(\d\d)/g; # finds "44" =begin original Typically you use the C<\G> anchor with the C flag when you want to try a different match if one fails, such as in a tokenizer. Jeffrey Friedl offers this example which works in 5.004 or later. =end original 典型的には、トークナイザのようなものの中で、一つのマッチングに失敗した ときに他のマッチングを試したいときに、C<\G> アンカーに C フラグを つけて使います。 Jeffrey Friedl が、5.004 以降で動作する、これに関する例を提供してくれました。 while (<>) { chomp; PARSER: { m/ \G( \d+\b )/gcx && do { print "number: $1\n"; redo; }; m/ \G( \w+ )/gcx && do { print "word: $1\n"; redo; }; m/ \G( \s+ )/gcx && do { print "space: $1\n"; redo; }; m/ \G( [^\w\d]+ )/gcx && do { print "other: $1\n"; redo; }; } } =begin original For each line, the C loop first tries to match a series of digits followed by a word boundary. This match has to start at the place the last match left off (or the beginning of the string on the first match). Since C uses the C flag, if the string does not match that regular expression, perl does not reset pos() and the next match starts at the same position to try a different pattern. =end original それぞれの行において、C ループはまず数字の列に引き続く単語境界に マッチングしようと試みます。 このマッチングは直前のマッチングが行われた場所(最初のマッチングの場合は 文字列の先頭)から始められなければなりません。 C は C フラグを使っているので、もし文字列がこの 正規表現にマッチングしなければ、perl は pos() をリセットせず、次の マッチングは、他のパターンを試す場合でも同じ位置から開始します。 =head2 Are Perl regexes DFAs or NFAs? Are they POSIX compliant? X X X (Perl の正規表現ルーチンは DFA ですか NFA ですか? また、それは POSIX に従ってますか?) =begin original While it's true that Perl's regular expressions resemble the DFAs (deterministic finite automata) of the egrep(1) program, they are in fact implemented as NFAs (non-deterministic finite automata) to allow backtracking and backreferencing. And they aren't POSIX-style either, because those guarantee worst-case behavior for all cases. (It seems that some people prefer guarantees of consistency, even when what's guaranteed is slowness.) See the book "Mastering Regular Expressions" (from O'Reilly) by Jeffrey Friedl for all the details you could ever hope to know on these matters (a full citation appears in L). =end original Perl の正規表現は egrep(1) の DFA (deterministic finite automata, 決定性有限オートマトン)と似たものではあるのですが、 実際のところはバックトラックや後方参照 (backreferencing)のために NFA として実装されています。 そして、Perl の正規表現は POSIX 形式のものでもありません。 なぜなら、それはすべてのケースにおいて最悪の振る舞いを行うからです (一部の人は、それが遅さをもたらすにもかからわず、一貫性をもたらすという点を 好んでいるようです)。 上記のことなどに関しての詳細は Jeffrery Friedl による O'Reilly から 出版されている "Mastering Regular Expressions" という本を参照してください。 =head2 What's wrong with using grep in a void context? X (無効コンテキストで grep を使うことのどこが間違っているのでしょうか?) =begin original The problem is that grep builds a return list, regardless of the context. This means you're making Perl go to the trouble of building a list that you then just throw away. If the list is large, you waste both time and space. If your intent is to iterate over the list, then use a for loop for this purpose. =end original 問題は、grep はそのコンテキストには関係なくリストを返すことです。 これはつまり、Perl にあなたが無視してしまうための戻り値のリストを 作らせるということです。 もしリストが大きいなら、時間とメモリの両方を無駄にします。 あなたの目的がリスト全体に対して反復することなら、for ループを 使ってください。 =begin original In perls older than 5.8.1, map suffers from this problem as well. But since 5.8.1, this has been fixed, and map is context aware - in void context, no lists are constructed. =end original 5.8.1 より前の perl では、map も同じ問題の影響を受けていました。 しかし 5.8.1 から、これは修正され、map はコンテキストを 認識するようになりました - 無効コンテキストではリストは作られません。 =head2 How can I match strings with multibyte characters? X X X X X (マルチバイト文字を含む文字列をマッチングさせるには?) =begin original Starting from Perl 5.6 Perl has had some level of multibyte character support. Perl 5.8 or later is recommended. Supported multibyte character repertoires include Unicode, and legacy encodings through the Encode module. See L, L, and L. =end original Perl 5.6 から、Perl にはあるレベルのマルチバイト文字サポートがあります。 Perl 5.8 以降を推奨します。 対応するマルチバイト文字のレパートリーには、Unicode と、Encode モジュール 経由のレガシーエンコーディングを含みます。 L, L, L を参照してください。 =begin original If you are stuck with older Perls, you can do Unicode with the L module, and character conversions using the L and L modules. If you are using Japanese encodings, you might try using the jperl 5.005_03. =end original もしもっと古い Perl に捕まっているなら、L モジュールで Unicode ができ、L と L のモジュールを使って 文字変換ができます。 日本語エンコーディングを使っているなら、jperl 5.005_03 を使ってみたいかも しれません。 =begin original Finally, the following set of approaches was offered by Jeffrey Friedl, whose article in issue #5 of The Perl Journal talks about this very matter. =end original 最後に、The Perl Journal の第五号でこの問題についてより詳しい記事を書いた Jeffery Friedl により提案された手法の幾つかを挙げます。 =begin original Let's suppose you have some weird Martian encoding where pairs of ASCII uppercase letters encode single Martian letters (i.e. the two bytes "CV" make a single Martian letter, as do the two bytes "SG", "VS", "XX", etc.). Other bytes represent single characters, just like ASCII. =end original さて、ここで ASCII の大文字二文字で火星語の符号化をしていると仮定しましょう (たとえば、"CV", "SG", "VS", "XX" などといった二バイトの並びが 火星語の一文字を表わすということです)。 その他のバイトは ASCII と同様単一の文字を表現します。 =begin original So, the string of Martian "I am CVSGXX!" uses 12 bytes to encode the nine characters 'I', ' ', 'a', 'm', ' ', 'CV', 'SG', 'XX', '!'. =end original ですから、火星語の符号化をしている 12 バイトの "I am CVSGXX!" 文字列は、 'I', ' ', 'a', 'm', ' ', 'CV', 'SG', 'XX', '!' という九文字で構成されます。 =begin original Now, say you want to search for the single character C. Perl doesn't know about Martian, so it'll find the two bytes "GX" in the "I am CVSGXX!" string, even though that character isn't there: it just looks like it is because "SG" is next to "XX", but there's no real "GX". This is a big problem. =end original ここで、C という一文字検索をしたいと考えてみましょう。 Perl は火星語については何も知りませんから、"I am CVSGXX!" という文字列にある "GX" 二バイトを見つけ出してしまうでしょうが、これは文字としてそこに あるものではありません: つまり、"SG" に続けて "XX" があるのでそう 見えるだけであって、本当に "GX" があるわけではないのです。 これは大きな問題です。 =begin original Here are a few ways, all painful, to deal with it: =end original この問題に対処する方法が、どれもうんざりするようなものですが、幾つかあります: # Make sure adjacent "martian" bytes are no longer adjacent. $martian =~ s/([A-Z][A-Z])/ $1 /g; print "found GX!\n" if $martian =~ /GX/; =begin original Or like this: =end original あるいは: my @chars = $martian =~ m/([A-Z][A-Z]|[^A-Z])/g; # above is conceptually similar to: my @chars = $text =~ m/(.)/g; # foreach my $char (@chars) { print "found GX!\n", last if $char eq 'GX'; } =begin original Or like this: =end original あるいは: while ($martian =~ m/\G([A-Z][A-Z]|.)/gs) { # \G probably unneeded if ($1 eq 'GX') { print "found GX!\n"; last; } } =begin original Here's another, slightly less painful, way to do it from Benjamin Goldberg, who uses a zero-width negative look-behind assertion. =end original 以下は Benjamin Goldberg による、同じことをもう少しましに行うもので、 ゼロ幅否定前方参照アサーションを使っています。 print "found GX!\n" if $martian =~ m/ (? X X X X<\Q, regex> X<\E, regex> X (変数に入っている正規表現でマッチングを行うには?) =begin original (contributed by brian d foy) =end original (brian d foy によって寄贈されました) =begin original We don't have to hard-code patterns into the match operator (or anything else that works with regular expressions). We can put the pattern in a variable for later use. =end original マッチング演算子(あるいはその他の正規表現として働くもの)にパターンを ハードコーディングする必要はありません。 後で使うためにパターンを変数に入れることができます。 =begin original The match operator is a double quote context, so you can interpolate your variable just like a double quoted string. In this case, you read the regular expression as user input and store it in C<$regex>. Once you have the pattern in C<$regex>, you use that variable in the match operator. =end original マッチング演算子はダブルクォートコンテキストなので、ダブルクォート文字列と 同様に変数展開できます。 個の場合、正規表現をユーザー入力として読み込んで、C<$regex> に保管します。 パターンが C<$regex> に入れば、この変数をマッチング演算子の中で使えます。 chomp( my $regex = ); if( $string =~ m/$regex/ ) { ... } =begin original Any regular expression special characters in C<$regex> are still special, and the pattern still has to be valid or Perl will complain. For instance, in this pattern there is an unpaired parenthesis. =end original C<$regex> 内の全ての正規表現特殊文字は特殊なままで、パターンが 有効でなければ Perl はエラーを出します。 例えば、このパターンには組になっていないかっこがあります。 my $regex = "Unmatched ( paren"; "Two parens to bind them all" =~ m/$regex/; =begin original When Perl compiles the regular expression, it treats the parenthesis as the start of a memory match. When it doesn't find the closing parenthesis, it complains: =end original Perl が正規表現をコンパイルする時に、かっこをマッチング記憶の開始として 扱います。 閉じかっこが見つからないと、エラーが出ます: Unmatched ( in regex; marked by <-- HERE in m/Unmatched ( <-- HERE paren/ at script line 3. =begin original You can get around this in several ways depending on our situation. First, if you don't want any of the characters in the string to be special, you can escape them with C before you use the string. =end original 状況に依存して、いくつかの方法でこれを回避できます。 まず、文字列中のどの文字も特別ではないなら、文字列を使う前に C でエスケープできます。 chomp( my $regex = ); $regex = quotemeta( $regex ); if( $string =~ m/$regex/ ) { ... } =begin original You can also do this directly in the match operator using the C<\Q> and C<\E> sequences. The C<\Q> tells Perl where to start escaping special characters, and the C<\E> tells it where to stop (see L for more details). =end original C<\Q> と C<\E> のシーケンスを使うことで、これをマッチング演算子の中で直接 行うこともできます。 C<\Q> は Perl に特殊文字のエスケープを開始する位置を示し、C<\E> はそれを 終了する位置を示します (さらなる詳細については L を 参照してください)。 chomp( my $regex = ); if( $string =~ m/\Q$regex\E/ ) { ... } =begin original Alternately, you can use C, the regular expression quote operator (see L for more details). It quotes and perhaps compiles the pattern, and you can apply regular expression flags to the pattern. =end original あるいは、正規表現クォート演算子である C が使えます(さらなる 詳細については L を参照してください)。 これはパターンをクォートし、おそらくはコンパイルされます; また、パターンに正規表現フラグを適用できます。 chomp( my $input = ); my $regex = qr/$input/is; $string =~ m/$regex/ # same as m/$input/is; =begin original You might also want to trap any errors by wrapping an C block around the whole thing. =end original 全体を C ブロックで包むことで全てのエラーをトラップしたいかも しれません。 chomp( my $input = ); eval { if( $string =~ m/\Q$input\E/ ) { ... } }; warn $@ if $@; =begin original Or... =end original または... my $regex = eval { qr/$input/is }; if( defined $regex ) { $string =~ m/$regex/; } else { warn $@; } =head1 AUTHOR AND COPYRIGHT Copyright (c) 1997-2010 Tom Christiansen, Nathan Torkington, and other authors as noted. All rights reserved. This documentation is free; you can redistribute it and/or modify it under the same terms as Perl itself. Irrespective of its distribution, all code examples in this file are hereby placed into the public domain. You are permitted and encouraged to use this code in your own programs for fun or for profit as you see fit. A simple comment in the code giving credit would be courteous but is not required. =begin meta Translate: 吉村 寿人 Update: SHIRAKATA Kentaro (5.6.1-5.14.1, 5.00150039) Status: completed =end meta