- 名前
- 説明
- 判読し難い、保守できないようなものにすることなく正規表現を使うには?
- 二行以上に対するマッチングでトラブルがありました。何が悪いのでしょう?
- 異なる行にある二つのパターンに挟まれている行を取り出すのはどうやればできますか?
- XML, HTML あるいはその他の扱いにくくて不細工なものを正規表現でマッチングさせるには?
- $/ に正規表現を入れたけど動きません。何が悪いの?
- 演算子の左辺では大小文字を無視して、演算子の右辺では元の大小文字を保存しておくような置換をするには?
- How can I make
\w
match national character sets? - How can I match a locale-smart version of
/[a-zA-Z]/
? - 正規表現の中で使う変数をクォートするには?
- What is
/o
really for? - ファイルから、C 形式のコメントを剥ぎ取る(strip)するにはどのように正規表現を使えば良いのでしょうか?
- Perl の正規表現をバランスされたテキストのマッチングに使えますか?
- 正規表現が貪欲(greedy)であるとはどういうことですか?
- 各行の単語単位に処理をするにはどうすれば良いですか?
- 語の出現頻度や行の出現頻度のまとめを出力するには?
- 曖昧なマッチング (approximate matching) はどうやればできますか?
- たくさんの正規表現を一度に効率良くマッチングするには?
- Why don't word-boundary searches with
\b
work for me? - なぜ $&, $`, $' を使うとプログラムが遅くなるの?
- What good is
\G
in a regular expression? - Perl の正規表現ルーチンは DFA ですか NFA ですか? また、それは POSIX に従ってますか?
- 無効コンテキストで grep を使うことのどこが間違っているのでしょうか?
- マルチバイト文字を含む文字列をマッチングさせるには?
- 変数に入っている正規表現でマッチングを行うには?
- AUTHOR AND COPYRIGHT
名前¶
perlfaq6 - Regular Expressions
perlfaq6 - 正規表現
説明¶
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 are handled with regular expressions, but those answers are found elsewhere in this document (in perlfaq9: "How do I decode or create those %-encodings on the web" and perlfaq4: "How do I determine whether a scalar is a number/whole/integer/float", to be precise).
この章は驚くほど小さくなっています。 なぜならFAQの残りの部分は 正規表現を伴った回答と一緒にあちこちに散在しているからです。 たとえばURLをデコードするとかあるものが数値かどうか確認することは 正規表現を使って処理されますが、この回答はこの資料のあらゆる所で 見つけることができます(正確には perlfaq9: "How do I decode or create those %-encodings on the web" と perlfaq4: "How do I determine whether a scalar is a number/whole/integer/float")。
判読し難い、保守できないようなものにすることなく正規表現を使うには?¶
Three techniques can make regular expressions maintainable and understandable.
正規表現を保守可能なものにし、理解できるようにするための 三つの技法があります。
- Comments Outside the Regex
-
(正規表現の外側にコメントを付ける)
Describe what you're doing and how you're doing it, using normal Perl comments.
通常の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;
- Comments Inside the Regex
-
(正規表現の内側にコメントを付ける)
The
/x
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.<CODE>/x</CODE> 修飾子は、正規表現中にある空白を無視するようにし、 (文字クラスの中とその他いくつかにあるものを除く)、通常のコメントが使えるように します。 あなたの想像できるように、空白とコメントは非常に助けに なります。
/x
lets you turn this:/x
によってs{<(?:[^>'"]*|".*?"|'.*?')+>}{}gs;
into this:
この正規表現を以下の様に記述できます:
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
It's still not quite so clear as prose, but it is very useful for describing the meaning of each part of the pattern.
これでもまだ散文(prose)程には明確にはなっていませんが、 パターンの各部分の意味を説明するには非常に便利なものです。
- Different Delimiters
-
(異なった区切り)
While we normally think of patterns as being delimited with
/
characters, they can be delimited by almost any character. perlre describes this. For example, thes///
above uses braces as delimiters. Selecting another delimiter can avoid quoting the delimiter within the pattern:私たちは通常、
/
で区切られたものをパターンであると考えていますが、 パターンはほとんどすべてのキャラクタを使って区切ることが可能です。 perlreはこれを説明しています。 たとえば、先に挙げたs///
では、区切りとしてカーリーブレースを使っています。 スラッシュ以外の区切りを選択することによって、パターンの中に存在する 区切り記号と同じものをクォートする手間を省くことができます。s/\/usr\/local/\/usr\/share/g; # bad delimiter choice s#/usr/local#/usr/share#g; # better
二行以上に対するマッチングでトラブルがありました。何が悪いのでしょう?¶
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).
マッチングの対象となっている文字列が実際には二行以上になっていないか、 パターンで正しい修飾子 (modifier)を使っていないかのいずれかでしょう (多分)。
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 undef
for the whole file) to allow you to read more than one line at a time.
複数行のデータを一つの文字列にする方法はたくさんあります。 これを、入力を読み込んでいる間自動で行なわせたいというのであれば、 一度に二行以上読ませるために $/を(パラグラフ単位で読み込みたいなら '' を、 ファイル全体を読み込みたいなら undef
を)設定したくなるでしょう。
Read perlre to help you decide which of /s
and /m
(or both) you might want to use: /s
allows dot to include newline, and /m
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.
あなたが使いたいのは /s
か /m
のいずれなのか(あるいはこれら 両方なのか)を決めるのを助けるために、perlre を読んでください: /s
はドットが改行を含むようにしますし、/m
はキャレットとドル記号が 文字列の両端だけでなく改行の前後でマッチするようにします。 そして、複数行に渡る文字列を取得するようにさせる必要があります。
For example, this program detects duplicate words, even when they span line breaks (but not paragraph ones). For this example, we don't need /s
because we aren't using dot in a regular expression that we want to cross line boundaries. Neither do we need /m
because we aren't wanting 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.
たとえば、以下に挙げるプログラムは重複した単語を、たとえそれが行を またがっていても(ただしパラグラフはまたがっていない)探し出すものです。 この例では、/s
の必要はありません。 なぜなら、この行をまたがらせたい正規表現でドットを使っていないからです。 /m
を使う必要もありません。 それは、キャレットやドル記号をレコードの中にある改行の前後で マッチさせることは望んでいないからです。 しかし、$/ をデフォルト以外のものに設定することは避けられませんし、 そうしなければ複数行レコードを読み込むことはできないのです。
$/ = ''; # 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";
}
}
Here's code that finds sentences that begin with "From " (which would be mangled by many mailers):
以下の例は、“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";
}
}
Here's code that finds everything between START and END in a paragraph:
次の例は、パラグラフ中の 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";
}
}
異なる行にある二つのパターンに挟まれている行を取り出すのはどうやればできますか?¶
You can use Perl's somewhat exotic ..
operator (documented in perlop):
Perlの ..
演算子を使えます(perlop に説明があります)。
perl -ne 'print if /START/ .. /END/' file1 file2 ...
If you wanted text and not lines, you would use
行ではなく、テキストが必要なら次のようにします
perl -0777 -ne 'print "$1\n" while /START(.*?)END/gs' file1 file2 ...
But if you want nested occurrences of START
through END
, you'll run up against the problem described in the question in this section on matching balanced text.
しかし、START
と END
が現れるのを入れ子にさせたいというのであれば、 このセクションにある質問で説明されている問題に直面することになります。
Here's another example of using ..
:
..
を使った別の例です:
while (<>) {
$in_header = 1 .. /^$/;
$in_body = /^$/ .. eof;
# now choose between them
} continue {
$. = 0 if eof; # fix $.
}
XML, HTML あるいはその他の扱いにくくて不細工なものを正規表現でマッチングさせるには?¶
(contributed by brian d foy)
(brian d foy によって寄贈されました)
If you just want to get work done, use a module and forget about the regular expressions. The XML::Parser
and HTML::Parser
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 ( http://search.cpan.org ) and wonder at all the work people have done for you already! :)
単に作業をすませたいだけなら、モジュールを使って、正規表現のことは 忘れてください。 XML::Parser
モジュールと HTML::Parser
モジュールはいい開始点ですが、 それぞれの名前空間は、特定の処理に特化したり、、それを行うための異なった方法の ための他のパースモジュールを持ちます。 CPAN Search ( http://search.cpan.org ) から始めて、あなたのための作業を 既にしてくれている人がいないかどうかを探してみてください! :)
The problem with things such as XML is that they have balanced text containing multiple levels of balanced text, but sometimes it isn't balanced text, as in an empty tag (<br/>
, for instance). Even then, things can occur out-of-order. Just when you think you've got a pattern that matches your input, someone throws you a curveball.
XML のようなものの問題点は、複数レベルのバランスされたテキストを含む バランスされたテキストでありながら、ときどき空タグ (例えば <br/>
)のようにバランスされていない テキストがあることです。 それでも、予定外のことが起こります。 入力を処理するためのパターンが出来た、と思った瞬間、誰かが あなたに変化球を投げてきます。
If you'd like to do it the hard way, scratching and clawing your way toward a right answer but constantly being disappointed, besieged by bug reports, and weary from the inordinate amount of time you have to spend reinventing a triangular wheel, then there are several things you can try before you give up in frustration:
もしあなたが、正しい答えだけれども絶えず失望するような方法に道にひっかかれ、 バグ報告に包囲され、 3 角形の車輪を再開発するために費やす大量の時間に辟易とするような 厳しい道を望むなら、 フラストレーションで諦める前に試すことの出来ることがいくつかあります:
Solve the balanced text problem from another question in perlfaq6
(perlfaq6 にある、バランスされたテキストに関するその他の問題を解決する。)
Try the recursive regex features in Perl 5.10 and later. See perlre
(Perl 5.10 以降の再帰パターンマッチング機能を試す。perlre を参照してください。)
Try defining a grammar using Perl 5.10's
(?DEFINE)
feature.(Perl 5.10 の
(?DEFINE)
機能を使った文法の定義を試す。)Break the problem down into sub-problems instead of trying to use a single regex
(単一の正規表現で処理せずに、複数の副問題に分割する。)
Convince everyone not to use XML or HTML in the first place
(第 1 に XML や HTML を使わないようにみんなを説得する。)
Good luck!
がんばって!
$/ に正規表現を入れたけど動きません。何が悪いの?¶
$/ has to be a string. You can use these examples if you really need to do this.
$/ は文字列でなければなりません。 もし本当にそうする必要があるなら、以下の例が使えます。
If you have File::Stream, this is easy.
もし File::Stream があれば、簡単です。
use File::Stream;
my $stream = File::Stream->new(
$filehandle,
separator => qr/\s*,\s*/,
);
print "$_\n" while <$stream>;
If you don't have File::Stream, you have to do a little more work.
File::Stream がなければ、もう少し作業が必要です。
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).
継続的にバッファに追加するために、sysread の 4 引数形式が使えます。 バッファに追加した後、(正規表現を使って)行全体が揃っているかを チェックします。
local $_ = "";
while( sysread FH, $_, 8192, length ) {
while( s/^((?s).*?)your_pattern// ) {
my $record = $1;
# do stuff here.
}
}
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.
もしファイル全体を最後までメモリに入れることを気にしないのなら、 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;
}
演算子の左辺では大小文字を無視して、演算子の右辺では元の大小文字を保存しておくような置換をするには?¶
Here's a lovely Perlish solution by Larry Rosler. It exploits properties of bitwise xor on ASCII strings.
以下に 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;
And here it is as a subroutine, modeled after the above:
以下はサブルーチンにしたものです。 上記と同じ手法です:
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";
This prints:
これは以下のように表示します:
this is a SUcCESS case
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:
代替案として、もし元のものの方が長い場合には置き換え単語の大文字小文字を 維持する場合は、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);
}
This changes the sentence to "this is a SUcCess case."
これは文章を "this is a SUcCess case." に変更します。
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.
もしもっと 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;
}
How can I make \w
match national character sets? ¶
(\w
がローカルな文字セットにマッチするようにするには?)
Put use locale;
in your script. The \w character class is taken from the current locale.
use locale;
をスクリプトに書いてください。 \w 文字クラスが現在のロケールから取られるようになります。
See perllocale for details.
詳しくは perllocale を参照してください。
How can I match a locale-smart version of /[a-zA-Z]/
? ¶
(/[a-zA-Z]/
の locale-smart なバージョンでマッチさせるには?)
You can use the POSIX character class syntax /[[:alpha:]]/
documented in perlre.
perlre で記述されている、POSIX 文字クラス文法 /[[:alpha:]]/
が 使えます。
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 /[^\W\d_]/
. Its complement, the non-alphabetics, is then everything in \W along with the digits and the underscore, or /[\W\d_]/
.
あなたがどこにいるかに関わらず、英文字は \w から数字と下線を除いたものです。 正規表現としては、これは /[^\W\d_]/
のようになります。 その逆である非英字は、\W に含まれる全ての文字に数字と下線を加えたもの、 つまり /[\W\d_]/
です。
正規表現の中で使う変数をクォートするには?¶
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 s///
substitution is considered a double-quoted string (see perlop 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:
Perlの構文解析器(parser)は、区切りがシングルクォーテーションでない限り、 正規表現の中にある $variable や @variable といったものを展開します。 s///
による置換の右側にあるものはダブルクォーテーションで 括られた文字列とみなされるということを忘れないでください。 また、すべての正規表現演算子はその前に \Q を置いておかないと、 正規表現演算子として振る舞うということも忘れないでください。 以下に例を挙げます。
$string = "Placido P. Octopus";
$regex = "P.";
$string =~ s/$regex/Polyp/;
# $string is now "Polypacido P. Octopus"
Because .
is special in regular expressions, and can match any single character, the regex P.
here has matched the <Pl> in the original string.
.
正規表現では特別で、任意の 1 文字にマッチングするので、 ここでの P.
は元の文字列の <Pl> にマッチングします。
To escape the special meaning of .
, we use \Q
:
.
の特殊な意味をエスケープするには、\Q
を使います:
$string = "Placido P. Octopus";
$regex = "P.";
$string =~ s/\Q$regex/Polyp/;
# $string is now "Placido Polyp Octopus"
The use of \Q
causes the <.> in the regex to be treated as a regular character, so that P.
matches a P
followed by a dot.
\Q
を使うことによって、正規表現中の .
は通常の文字として扱われるので、 P.
は P
の後にピリオドがあるものにマッチングします。
What is /o
really for? ¶
(/o
は実際なんのためのものなのですか?)
(contributed by brian d foy)
(brian d foy によって寄贈されました)
The /o
option for regular expressions (documented in perlop and perlreref) 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.
正規表現の /o
オプション (perlop と perlreref で文書化されています) は、正規表現を一度だけコンパイルするように Perl に伝えます。 これはパターンに変数が含まれている場合にのみ有用です。 Perls 5.6 以降では、パターンが変わらない場合はこれを自動的に扱います。
Since the match operator m//
, the substitution operator s///
, and the regular expression quoting operator qr//
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.
マッチング演算子 m//
, 置換演算子 s///
, 正規表現クォート演算子 qr//
はダブルクォート風構造なので、パターン中で変数を展開できます。 詳細については "How can I quote a variable to use in a regex?" の答えを 参照してください。
This example takes a regular expression from the argument list and prints the lines of input that match it:
この例は正規表現を引数リストから取って、それにマッチングする入力行を 表示します:
my $pattern = shift @ARGV;
while( <> ) {
print if m/$pattern/;
}
Versions of Perl prior to 5.6 would recompile the regular expression for each iteration, even if $pattern
had not changed. The /o
would prevent this by telling Perl to compile the pattern the first time, then reuse that for subsequent iterations:
バージョン 5.6 より前の Perl では、$pattern
に変更がなくても反復毎に 正規表現が再コンパイルされます。 /o
をつけると、パターンを初回にコンパイルし、引き続く反復では 再利用するように Perl に伝えることで、再コンパイルを防ぎます:
my $pattern = shift @ARGV;
while( <> ) {
print if m/$pattern/o; # useful for Perl < 5.6
}
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 /o
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 /o
.
バージョン 5.6 以降では、変数が変更されていない場合は Perl は正規表現を 再コンパイルしませんので、おそらく /o
は不要です。 害はもたらしませんが、助けにもなりません。 どのバージョンでも、たとえ変数の値が変わっても正規表現を一度だけ コンパイルするようにしたい場合は、未だに /o
が必要です。
You can watch Perl's regular expression engine at work to verify for yourself if Perl is recompiling a regular expression. The use re 'debug'
pragma (comes with Perl 5.005 and later) shows the details. With Perls before 5.6, you should see re
reporting that its compiling the regular expression on each iteration. With Perl 5.6 or later, you should only see re
report that for the first iteration.
Perl が正規表現を再コンパイルしたときに自分自身で検証するために、動作中の Perl の正規表現エンジンを見守ることもできます。 use re 'debug'
プラグマ (Perl 5.005 以降で実装されています) は詳細を 表示します。 5.6 より前の Perl では、各反復で正規表現がコンパイルされる毎に re
の 報告を見ることになります。 Perl 5.6 以降では、最初の反復でのみ re
の報告を見ることになります。
use re 'debug';
$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/;
}
ファイルから、C 形式のコメントを剥ぎ取る(strip)するにはどのように正規表現を使えば良いのでしょうか?¶
While this actually can be done, it's much harder than you'd think. For example, this one-liner
実際これは可能なのですが、あなたが考えているよりも非常に難しいものです。 たとえば次の一行野郎 (one-liner) はほとんどの場合にうまく行きますが、 すべての場合ではありません。
perl -0777 -pe 's{/\*.*?\*/}{}gs' foo.c
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.
そう、これは C のプログラムを簡単に考えすぎているのです。 特に、クォートされた文字列にコメントが出現するということを考慮していません。 このため、Jeffrey Friedl が作成し、後に Fred Curtis によって修正された 次の例のようなことが必要になります。
$/ = undef;
$_ = <>;
s#/\*[^*]*\*+([^/*][^*]*\*+)*/|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)#defined $2 ? $2 : ""#gse;
print;
This could, of course, be more legibly written with the /x
modifier, adding whitespace and comments. Here it is expanded, courtesy of Fred Curtis.
もちろんこれは、/x
修飾子を使って空白やコメントを付加することで、 より読みやすくすることが可能です。 以下は 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;
A slight modification also removes C++ comments, possibly spanning multiple lines using a continuation character:
(継続文字を使って複数行にわたっていない限りは) 少しの変更で、おそらくは継続文字を使った複数行にわたるものも含む、 C++ コメントも除去します:
s#/\*[^*]*\*+([^/*][^*]*\*+)*/|//([^\\]|[^\n][\n]?)*?\n|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)#defined $3 ? $3 : ""#gse;
Perl の正規表現をバランスされたテキストのマッチングに使えますか?¶
(contributed by brian d foy)
(brian d foy によって寄贈されました)
Your first try should probably be the Text::Balanced
module, which is in the Perl standard library since Perl 5.8. It has a variety of functions to deal with tricky text. The Regexp::Common
module can also help by providing canned patterns you can use.
おそらく、まずはじめに試すべきなのは、Perl 5.8 から Perl 標準ライブラリに なっている Text::Balanced
モジュールです。 これには扱いにくい文章を扱うための様々な関数があります。 Regexp::Common
モジュールも、すぐ使えるパターンを提供することで 手助けしてくれます。
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 (??{})
sequences.
Perl 5.10 以降では、再帰パターンを使って正規表現でバランスされた テキストをマッチングすることが出来ます。 Perl 5.10 以前では、(??{})
シーケンス内で Perl コードを使うといった さまざまな技を使う必要があります。
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:
以下は再帰的正規表現を使った例です。 ゴールは、(ネストしたものを含む)山かっこ内の全てのテキストを 捕らえることです。 サンプルの文章には二つの「主な」グループがあります: 1 レベルの ネストがあるものと、2 レベルのネストがあるものです。 これは全部で五つの山かっこグループがあります:
I have some <brackets in <nested brackets> > and
<another group <nested once <nested twice> > >
and that's it.
The regular expression to match the balanced text uses two new (to Perl 5.10) regular expression features. These are covered in perlre and this example is a modified version of one in that documentation.
バランスされたテキストにマッチングする正規表現は二つの新しい (Perl 5.10 以降の)正規表現の機能を使います。 これらは perlre で説明されていて、この例はその文書にあるものの 修正版です。
First, adding the new possessive +
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 [^<>]++
finds one or more non-angle brackets without backtracking.
まず、絶対量指定子を追加することで、 最大マッチングを行って、バックトラックをしません。 これは、山かっこをバックトラッキングではなく再帰で扱いたいので 重要です。 グループ [^<>]++
は、一つまたは複数の、山かっこでないものを バックトラッキングなしで探し出します。
Second, the new (?PARNO)
refers to the sub-pattern in the particular capture group given by PARNO
. 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 (?1)
uses the pattern in the outer capture group as an independent part of the regex.
次に、新しい (?PARNO)
は、PARNO
で与えられる特定の捕捉バッファ内の 副パターンを参照します。 以下の正規表現では、最初の捕捉バッファがバランスされたテキストを 発見し(さらに保存し)、ネストしたテキストを調べるために最初のバッファ内に 同じパターンを適用する必要があります。 (?1)
は、外側の捕捉バッファのパターンを正規表現内の 独立した部分として使います。
Putting it all together, you have:
これを全てまとめると:
#!/usr/local/bin/perl5.10.0
my $string =<<"HERE";
I have some <brackets in <nested brackets> > and
<another group <nested once <nested twice> > >
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";
The output shows that Perl found the two major groups:
Perl が二つの主なグループを発見したことが出力されます:
Found:
<brackets in <nested brackets> >
<another group <nested once <nested twice> > >
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:
もう少し作業すれば、たとえ他の山かっこがあっても、全ての山かっこの グループを得られます。 バランスされたマッチングが得られる毎に、外側のデリミタを取り除いて (これは今マッチングしたモノにまたマッチングしないようにするためです)、 処理する文字列のキューに追加します。 これを、マッチングしなくなるまで繰り返します:
#!/usr/local/bin/perl5.10.0
my @queue =<<"HERE";
I have some <brackets in <nested brackets> > and
<another group <nested once <nested twice> > >
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/^<//; s/>$//; $_ } @groups;
}
The output shows all of the groups. The outermost matches show up first and the nested matches so up later:
全てのグループが出力されます。 一番外側のマッチングが最初に表示され、ネストしたマッチングはその後に なります:
Found:
<brackets in <nested brackets> >
<another group <nested once <nested twice> > >
Found:
<nested brackets>
Found:
<nested once <nested twice> >
Found:
<nested twice>
正規表現が貪欲(greedy)であるとはどういうことですか?¶
Most people mean that greedy regexes match as much as they can. Technically speaking, it's actually the quantifiers (?
, *
, +
, {}
) 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 (??
, *?
, +?
, {}?
).
ほとんどの人が、貪欲正規表現(greedy regexps)は可能な限りマッチすると 考えています。 技術的には、量指定子(?
, *
, +
, {}
) はパターン全体よりも貪欲です。 Perl は、全体的な貪欲性よりも局所貪欲性と即時の満足性を好みます。 同じ量指定子の non-greedy バージョンを得るには、 ??
, *?
, +?
, {}?
を使います。
An example:
例:
$s1 = $s2 = "I am very very cold";
$s1 =~ s/ve.*y //; # I am cold
$s2 =~ s/ve.*?y //; # I am very cold
Notice how the second substitution stopped matching as soon as it encountered "y ". The *?
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.
二番目の置換が、“y ”を見つけてすぐにマッチングを中断していることに 注目してください。 量指定子 *?
は正規表現エンジンに対して、あなたが熱いジャガイモを 扱っているときのように、可能な限り早くマッチするものを見つけて制御を次の行に 渡すように効果的に指示します。
各行の単語単位に処理をするにはどうすれば良いですか?¶
Use the split function:
split 関数を使います:
while (<>) {
foreach $word ( split ) {
# do something with $word here
}
}
Note that this isn't really a word in the English sense; it's just chunks of consecutive non-whitespace characters.
これは実際には英語でいうところの語ではないことに注意してください。 これは、単なる連続した空白でない文字の塊です。
To work with only alphanumeric sequences (including underscores), you might consider
アルファベットもしくは数字の並びのみを対象とするには以下のようにして できます。
while (<>) {
foreach $word (m/(\w+)/g) {
# do something with $word here
}
}
語の出現頻度や行の出現頻度のまとめを出力するには?¶
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:
これを行うためには、入力ストリームにある単語のそれぞれについて解析する 必要があります。 私たちはここで、一つ前の質問と同様に、非空白文字の塊を語と するのではなく、英字、ハイフン、アポストロフィ、の塊を語とします:
while (<>) {
while ( /(\b[^\W_\d][\w'-]+\b)/g ) { # misses "`sheep'"
$seen{$1}++;
}
}
while ( ($word, $count) = each %seen ) {
print "$count $word\n";
}
If you wanted to do the same thing for lines, you wouldn't need a regular expression:
同じことを行に対して行いたいのであれば、正規表現は必要ないでしょう。
while (<>) {
$seen{$_}++;
}
while ( ($line, $count) = each %seen ) {
print "$count $line";
}
If you want these output in a sorted order, see perlfaq4: "How do I sort a hash (optionally by value instead of key)?".
ソートされた順序で出力したいのなら、perlfaq4: "How do I sort a hash (optionally by value instead of key)?" を参照してください。
曖昧なマッチング (approximate matching) はどうやればできますか?¶
See the module String::Approx available from CPAN.
CPAN で入手できる String::Approx モジュールを参照してください。
たくさんの正規表現を一度に効率良くマッチングするには?¶
(contributed by brian d foy)
(brian d foy によって寄贈されました)
If you have Perl 5.10 or later, this is almost trivial. You just smart match against an array of regular expression objects:
Perl 5.10 以降では、これはほぼささいな問題です。 単に正規表現オブジェクトの配列に対してスマートマッチングします:
my @patterns = ( qr/Fr.d/, qr/B.rn.y/, qr/W.lm./ );
if( $string ~~ @patterns ) {
...
};
The smart match stops when it finds a match, so it doesn't have to try every expression.
マッチングするとスマートマッチングは停止するので、全ての正規表現を 試す必要はありません。
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 foreach
loop since it has no way to know what $pattern
will be:
Perl 5.10 より前では、少し作業が必要です。 マッチングを行う毎に Perl が正規表現をコンパイルすることを避けてください。 この例の場合、$pattern
が何者なのかを知る方法がないので、perl は foreach
ループの反復毎に正規表現を再コンパイルしなければなりません:
my @patterns = qw( foo bar baz );
LINE: while( <DATA> ) {
foreach $pattern ( @patterns ) {
if( /\b$pattern\b/i ) {
print;
next LINE;
}
}
}
The qr//
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 map
to turn each pattern into its pre-compiled form. The rest of the script is the same, but faster:
qr//
演算子は perl 5.005 で現れました。 これは正規表現をコンパイルしますが、適用はしません。 プリコンパイルされた正規表現を使うと、perl の作業は減ります。 この例では、各パターンをプリコンパイルされた形式に変換するための map()
を挿入しています。 スクリプトの残りの部分は同じですが、より速いです:
my @patterns = map { qr/\b$_\b/i } qw( foo bar baz );
LINE: while( <> ) {
foreach $pattern ( @patterns ) {
if( /$pattern/ )
{
print;
next LINE;
}
}
}
In some cases, you may be able to make several patterns into a single regular expression. Beware of situations that require backtracking though.
いくつかの場合では、複数のパターンを一つの正規表現にできるかもしれません。 しかし、バックトラッキングが必要になる状況に注意してください。
my $regex = join '|', qw( foo bar baz );
LINE: while( <> ) {
print if /\b(?:$regex)\b/i;
}
For more details on regular expression efficiency, see Mastering Regular Expressions by Jeffrey Friedl. He explains how regular expressions engine work and why some patterns are surprisingly inefficient. Once you understand how perl applies regular expressions, you can tune them for individual situations.
正規表現の効率に関するさらなる詳細については、Jeffrey Friedl による Mastering Regular Expressions を参照してください。 彼は、どのように正規表現エンジンが動作するかと、なぜある種のパターンが 驚くほど非効率かについて説明しています。 perl がどのように正規表現を適用するかを理解すれば、これらを個々の状況に 調整できます。
Why don't word-boundary searches with \b
work for me? ¶
(なぜ \b
を使った単語境界の検索がうまく行かないのでしょうか?)
(contributed by brian d foy)
(brian d foy によって寄贈されました)
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.
実際に \b が何を行うかをしっかり理解してください: これは単語文字 (\w) と、単語文字でない何かとの境界です。 単語文字でないというのは \W かもしれませんが、文字列の最初と最後にも あります。
It's not (not!) the boundary between whitespace and non-whitespace, and it's not the stuff between words we use to create sentences.
これは空白と非空白との境界ではなく(違うんです!)、私たちが文を作るのに 使う単語の間のものではありません。
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.
正規表現的に言うと、単語境界は (\b) は「ゼロ幅アサーション」です; これは文字列中の文字ではなく、ある位置での条件を表現しています。
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/.
正規表現 /\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"
These strings do not match /\bPerl\b/.
これらの文字列は /\bPerl\b/ にマッチングしません。
"Perl_" # _ is a word char!
"Perler" # no word char before P, but one after l
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/.
しかし、単語にマッチングさせるために \b を使う必要はありません。 単語文字に囲まれた非単語文字を探すのに使えます。 これらの文字列は、パターン /\b'\b/ にマッチングします。
"don't" # the ' char is surrounded by "n" and "t"
"qep'a'" # the ' char is surrounded by "p" and "a"
These strings do not match /\b'\b/.
これらの文字列は /\b'\b/ にマッチングしません。
"foo'" # there is no word char after non-word '
You can also use the complement of \b, \B, to specify that there should not be a word boundary.
単語境界ではないということを指定するために、\b の逆である \B も使えます。
In the pattern /\Bam\B/, there must be a word character before the "a" and after the "m". These patterns match /\Bam\B/:
パターン /\Bam\B/ では、"a" の前と "m" の後ろに単語文字が必要です。 これらはパターン /\Bam\B/ にマッチングします:
"llama" # "am" surrounded by word chars
"Samuel" # same
These strings do not match /\Bam\B/
これらの文字列は /\Bam\B/ にマッチングしません。
"Sam" # no word boundary before "a", but one after "m"
"I am Sam" # "am" surrounded by non-word chars
なぜ $&, $`, $' を使うとプログラムが遅くなるの?¶
(contributed by Anno Siegel)
(Anno Siegel によって寄贈されました)
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.
プログラムのどこかでそういった変数が使われているのを見つけてしまうと、 Perl はすべてのパターンマッチングに対してそれに対処することを やらなければなりません。 これは、全てのパターンマッチングに置いて、一部は $` に、一部は $& に、 一部は $' に、という形で文字列全体がコピーされるということを意味します。 従って、ペナルティは長い文字列とパターンを何度もマッチングさせるときに 最も厳しいものとなります。 可能であれば $& や $'、$` を使わないようにすべきなのですが、 それができないのであれば、一度これらの変数を使ってしまったら好きなように 使いましょう。 なぜなら、罰金はすでに払ってしまったのですから。 アルゴリズムの中にはこういった変数を使うことが適切であるものが あるということに注意してください。 リリース 5.005 からは、$& はもはや“高価な”ものではありません。
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.
Perl 5.6.1 から、特殊変数 @- と @+ で $`, $&, $' の機能を 置き換えられるようになりました。 これらの配列はそれぞれのマッチングの開始位置と終了位置へのポインタを 含みます(詳しい話については perlvar を参照してください)ので、 本質的にはこれらから同じ情報が得られますが、 過度の文字列コピーのリスクはありません。
Perl 5.10 added three specials, ${^MATCH}
, ${^PREMATCH}
, and ${^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 /p
modifier.
Perl 5.10 では、グローバルなペナルティなしに同じ作業をするための 3 つの特殊変数 ${^MATCH}
, ${^PREMATCH}
, ${^POSTMATCH}
が 追加されました。 Perl 5.10 では、正規表現を /p
修飾子付きでコンパイルしたり 実行したりした場合にのみこれらの変数がセットされます。
What good is \G
in a regular expression? ¶
(正規表現の中で \G
を使うと何が良いのですか?)
You use the \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 \G
is similar to the beginning of string anchor, ^
. The \G
anchor is typically used with the g
flag. It uses the value of pos()
as the position to start the next match. As the match operator makes successive matches, it updates pos()
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 pos()
value.
次のマッチングを同じ文字列のうち、前回のマッチングを中止したところから 始めるために \G
アンカーを使います。 正規表現エンジンはこのアンカーがあるときには次のマッチングを探すために 何の文字も読み飛ばさないので、\G
は文字列先頭アンカーである ^
と 似ています。 \G
アンカーは典型的には g
フラグと共に使います。 これは次のマッチングの開始位置として pos()
の値を使います。 マッチング演算子がマッチングに成功すると、pos()
の値を最後のマッチングの 次の文字(または次のマッチングの最初の文字; これはあなたがこれをどのように 見るかの問題です)の位置に更新します。 各文字列はそれぞれ独自の pos()
の値を持ちます。
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 11
and 22
but the letter <a> shows up between 22
and 44
and you want to stop at a
. Simply matching pairs of digits skips over the a
and still matches 44
.
"1122a44" のような文字列で、連続した数字のペアの全てにマッチングし、数字で ないものが現れたら停止したいとします。 11
と 22
にはマッチングしたいですが、22
と 44
の間に a
が 現れると、a
で停止したいとします。 数字のペアのマッチングは単に a
を読み飛ばし、引き続き 44
に マッチングします。
$_ = "1122a44";
my @pairs = m/(\d\d)/g; # qw( 11 22 44 )
If you use the \G
anchor, you force the match after 22
to start with the a
. 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.
\G
アンカーを使うと、22
の後のマッチングを a
から始めることを 強制します。 ここでは数字が見付からないのでマッチングできず、従って次のマッチングは 失敗してマッチング演算子は既に見付かったペアを返します。
$_ = "1122a44";
my @pairs = m/\G(\d\d)/g; # qw( 11 22 )
You can also use the \G
anchor in scalar context. You still need the g
flag.
スカラコンテキストにも \G
アンカーが使えます。 g
フラグはまだ必要です。
$_ = "1122a44";
while( m/\G(\d\d)/g )
{
print "Found $1\n";
}
After the match fails at the letter a
, perl resets pos()
and the next match on the same string starts at the beginning.
文字 a
のマッチングに失敗した後、perl は pos()
をリセットし、 同じ文字列に対する次のマッチングは先頭から行います。
$_ = "1122a44";
while( m/\G(\d\d)/g )
{
print "Found $1\n";
}
print "Found $1 after while" if m/(\d\d)/g; # finds "11"
You can disable pos()
resets on fail with the c
flag, documented in perlop and perlreref. Subsequent matches start where the last successful match ended (the value of pos()
) even if a match on the same string has failed in the meantime. In this case, the match after the while()
loop starts at the a
(where the last match stopped), and since it does not use any anchor it can skip over the a
to find 44
.
perlop と perlreref に書いているように、c
フラグをつけることで pos()
のリセットを抑制できます。 引き続くマッチングは、その間に同じ文字列でのマッチングが失敗していても、 直前の成功したマッチングが終了した場所 (pos()
の値) から開始されます。 この場合、while()
ループの後のマッチングは (最後のマッチングが停止した) a
から開始され、何のアンカーも使っていないので、44
を見つけるために a
をスキップできます。
$_ = "1122a44";
while( m/\G(\d\d)/gc )
{
print "Found $1\n";
}
print "Found $1 after while" if m/(\d\d)/g; # finds "44"
Typically you use the \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.
典型的には、トークナイザのようなものの中で、一つのマッチングに失敗した ときに他のマッチングを試したいときに、\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; };
}
}
For each line, the PARSER
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 m/ \G( \d+\b )/gcx
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.
それぞれの行において、PARSER
ループはまず数字の列に引き続く単語境界に マッチングしようと試みます。 このマッチングは直前のマッチングが行われた場所(最初のマッチングの場合は 文字列の先頭)から始められなければなりません。 m/ \G( \d+\b )/gcx
は c
フラグを使っているので、もし文字列がこの 正規表現にマッチングしなければ、perl は pos() をリセットせず、次の マッチングは、他のパターンを試す場合でも同じ位置から開始します。
Perl の正規表現ルーチンは DFA ですか NFA ですか? また、それは POSIX に従ってますか?¶
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 perlfaq2).
Perl の正規表現は egrep(1) の DFA (deterministic finite automata, 決定性有限オートマトン)と似たものではあるのですが、 実際のところはバックトラックや後方参照 (backreferencing)のために NFA として実装されています。 そして、Perl の正規表現は POSIX 形式のものでもありません。 なぜなら、それはすべてのケースにおいて最悪の振る舞いを行うからです (一部の人は、それが遅さをもたらすにもかからわず、一貫性をもたらすという点を 好んでいるようです)。 上記のことなどに関しての詳細は Jeffrery Friedl による O'Reilly から 出版されている "Mastering Regular Expressions" という本を参照してください。
無効コンテキストで grep を使うことのどこが間違っているのでしょうか?¶
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.
問題は、grep はそのコンテキストには関係なくリストを返すことです。 これはつまり、Perl にあなたが無視してしまうための戻り値のリストを 作らせるということです。 もしリストが大きいなら、時間とメモリの両方を無駄にします。 あなたの目的がリスト全体に対して反復することなら、for ループを 使ってください。
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.
5.8.1 より前の perl では、map も同じ問題の影響を受けていました。 しかし 5.8.1 から、これは修正され、map はコンテキストを 認識するようになりました - 無効コンテキストではリストは作られません。
マルチバイト文字を含む文字列をマッチングさせるには?¶
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 perluniintro, perlunicode, and Encode.
Perl 5.6 から、Perl にはあるレベルのマルチバイト文字サポートがあります。 Perl 5.8 以降を推奨します。 対応するマルチバイト文字のレパートリーには、Unicode と、Encode モジュール 経由のレガシーエンコーディングを含みます。 perluniintro, perlunicode, Encode を参照してください。
If you are stuck with older Perls, you can do Unicode with the Unicode::String
module, and character conversions using the Unicode::Map8
and Unicode::Map
modules. If you are using Japanese encodings, you might try using the jperl 5.005_03.
もしもっと古い Perl に捕まっているなら、Unicode::String
モジュールで Unicode ができ、Unicode::Map8
と Unicode::Map
のモジュールを使って 文字変換ができます。 日本語エンコーディングを使っているなら、jperl 5.005_03 を使ってみたいかも しれません。
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.
最後に、The Perl Journal の第五号でこの問題についてより詳しい記事を書いた Jeffery Friedl により提案された手法の幾つかを挙げます。
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.
さて、ここで ASCII の大文字二文字で火星語の符号化をしていると仮定しましょう (たとえば、"CV", "SG", "VS", "XX" などといった二バイトの並びが 火星語の一文字を表わすということです)。
So, the string of Martian "I am CVSGXX!" uses 12 bytes to encode the nine characters 'I', ' ', 'a', 'm', ' ', 'CV', 'SG', 'XX', '!'.
ですから、火星語の符号化をしている 12 バイトの "I am CVSGXX!" 文字列は、 'I', ' ', 'a', 'm', ' ', 'CV', 'SG', 'XX', '!' という九文字で構成されます。
Now, say you want to search for the single character /GX/
. 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.
ここで、/GX/
という一文字検索をしたいと考えてみましょう。 Perl は火星語については何も知りませんから、"I am CVSGXX!" という文字列にある "GX" 二バイトを見つけ出してしまうでしょうが、これは文字として そこにあるものではありません。 つまり、"SG" に続けて "XX" があるのでそう見えるだけであって、 本当に "GX" があるわけではないのです。 これは大きな問題です。
Here are a few ways, all painful, to deal with it:
この問題に対処する方法が、どれもうんざりするようなものですが、幾つかあります:
# Make sure adjacent "martian" bytes are no longer adjacent.
$martian =~ s/([A-Z][A-Z])/ $1 /g;
print "found GX!\n" if $martian =~ /GX/;
Or like this:
あるいは:
@chars = $martian =~ m/([A-Z][A-Z]|[^A-Z])/g;
# above is conceptually similar to: @chars = $text =~ m/(.)/g;
#
foreach $char (@chars) {
print "found GX!\n", last if $char eq 'GX';
}
Or like this:
あるいは:
while ($martian =~ m/\G([A-Z][A-Z]|.)/gs) { # \G probably unneeded
print "found GX!\n", last if $1 eq 'GX';
}
Here's another, slightly less painful, way to do it from Benjamin Goldberg, who uses a zero-width negative look-behind assertion.
以下は Benjamin Goldberg による、同じことをもう少しましに行うもので、 ゼロ幅否定前方参照アサーションを使っています。
print "found GX!\n" if $martian =~ m/
(?<![A-Z])
(?:[A-Z][A-Z])*?
GX
/x;
This succeeds if the "martian" character GX is in the string, and fails otherwise. If you don't like using (?<!), a zero-width negative look-behind assertion, you can replace (?<![A-Z]) with (?:^|[^A-Z]).
これはもし "martian" 文字 GX が文字列にあれば成功し、そうでなければ 失敗します。 ゼロ幅否定前方参照アサーション (?<!) を使いたくないなら、(?<![A-Z]) を (?:^|[^A-Z]) で置き換えられます。
It does have the drawback of putting the wrong thing in $-[0] and $+[0], but this usually can be worked around.
これには $-[0] と $+[0] に間違ったものが入るという欠点がありますが、普通 これは回避できます。
変数に入っている正規表現でマッチングを行うには?¶
(contributed by brian d foy)
(brian d foy によって寄贈されました)
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.
マッチング演算子(あるいはその他の正規表現として働くもの)にパターンを ハードコーディングする必要はありません。 後で使うためにパターンを変数に入れることができます。
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 $regex
. Once you have the pattern in $regex
, you use that variable in the match operator.
マッチング演算子はダブルクォートコンテキストなので、ダブルクォート文字列と 同様に変数展開できます。 個の場合、正規表現をユーザー入力として読み込んで、$regex
に保管します。 パターンが $regex
に入れば、この変数をマッチング演算子の中で使えます。
chomp( my $regex = <STDIN> );
if( $string =~ m/$regex/ ) { ... }
Any regular expression special characters in $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.
$regex
内の全ての正規表現特殊文字は特殊なままで、パターンが 有効でなければ Perl はエラーを出します。 例えば、このパターンには組になっていないかっこがあります。
my $regex = "Unmatched ( paren";
"Two parens to bind them all" =~ m/$regex/;
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:
Perl が正規表現をコンパイルする時に、かっこをマッチング記憶の開始として 扱います。 閉じかっこが見つからないと、エラーが出ます:
Unmatched ( in regex; marked by <-- HERE in m/Unmatched ( <-- HERE paren/ at script line 3.
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 quotemeta
before you use the string.
状況に依存して、いくつかの方法でこれを回避できます。 まず、文字列中のどの文字も特別ではないなら、文字列を使う前に quotemeta
でエスケープできます。
chomp( my $regex = <STDIN> );
$regex = quotemeta( $regex );
if( $string =~ m/$regex/ ) { ... }
You can also do this directly in the match operator using the \Q
and \E
sequences. The \Q
tells Perl where to start escaping special characters, and the \E
tells it where to stop (see perlop for more details).
\Q
と \E
のシーケンスを使うことで、これをマッチング演算子の中で直接 行うこともできます。 \Q
は Perl に特殊文字のエスケープを開始する位置を示し、\E
はそれを 終了する位置を示します (さらなる詳細については perlop を 参照してください)。
chomp( my $regex = <STDIN> );
if( $string =~ m/\Q$regex\E/ ) { ... }
Alternately, you can use qr//
, the regular expression quote operator (see perlop for more details). It quotes and perhaps compiles the pattern, and you can apply regular expression flags to the pattern.
あるいは、正規表現クォート演算子である qr//
が使えます(さらなる 詳細については perlop を参照してください)。 これはパターンをクォートし、おそらくはコンパイルされます; また、パターンに正規表現フラグを適用できます。
chomp( my $input = <STDIN> );
my $regex = qr/$input/is;
$string =~ m/$regex/ # same as m/$input/is;
You might also want to trap any errors by wrapping an eval
block around the whole thing.
全体を eval
ブロックで包むことで全てのエラーをトラップしたいかも しれません。
chomp( my $input = <STDIN> );
eval {
if( $string =~ m/\Q$input\E/ ) { ... }
};
warn $@ if $@;
Or...
または...
my $regex = eval { qr/$input/is };
if( defined $regex ) {
$string =~ m/$regex/;
}
else {
warn $@;
}
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.