英語フランス語スペイン語

OnWorksファビコン

perlfaq6-クラウドでのオンライン

Ubuntu Online、Fedora Online、Windows Onlineエミュレーター、またはMACOSオンラインエミュレーターを介してOnWorks無料ホスティングプロバイダーでperlfaq6を実行します

これは、Ubuntu Online、Fedora Online、Windowsオンラインエミュレーター、MACOSオンラインエミュレーターなどの複数の無料オンラインワークステーションの6つを使用してOnWorks無料ホスティングプロバイダーで実行できるコマンドperlfaqXNUMXです。

プログラム:

NAME


perlfaq6 - 正規表現

VERSION


バージョン5.021009

DESCRIPTION


FAQ の残りの部分には回答が散りばめられているため、このセクションは驚くほど小さいです
正規表現が関係します。 たとえば、URL をデコードして、何かがあるかどうかを確認します。
数値は正規表現で処理できますが、その答えは別の場所にあります
このドキュメント (perlfaq9 内: 「Web 上でこれらの % エンコーディングをデコードまたは作成するにはどうすればよいですか」)
perlfaq4: 「スカラーが数値/整数/整数/浮動小数点数であるかどうかを判断するにはどうすればよいですか」、
正確)。

認定条件 できる I 希望 〜へ つかいます レギュラー 表現 無し 作成 判読不能 保守不可能な コード?
正規表現を保守しやすく理解しやすくするには、XNUMX つのテクニックがあります。

正規表現外のコメント
通常の Perl コメントを使用して、何をしているのか、どのようにしているのかを説明します。

# 行を最初の単語、コロン、および
# 行の残りの文字数
s/^(\w+)(.*)/ lc($1) 。 「:」。 長さ($2) /メガ;

正規表現内のコメント
「/x」修飾子を使用すると、正規表現パターンで空白が無視されます (ただし、
文字クラスと他のいくつかの場所)、通常のコメントも使用できます
そこにもあります。 ご想像のとおり、空白とコメントは非常に役立ちます。

「/x」を使用すると、次のようになります。

s{<(?:[^>'"]*|".*?"|'.*?')+>}{}gs;

これに:

s{ < # 開始山括弧
(?: # 非逆参照グループ化括弧
[^>'"] * # > でも ' でも " でもないものを 0 個以上
| # それ以外の場合
「。*?」 # 二重引用符間のセクション (ケチマッチ)
| # それ以外の場合
「.*?」 # 一重引用符間のセクション (ケチマッチ)
) + # すべてが XNUMX 回以上発生する
> # 閉じ山括弧
}{}gsx; # 何も置き換えない、つまり削除します

まだ散文ほど明確ではありませんが、内容を説明するのに非常に役立ちます。
模様の各部分の意味。

さまざまな区切り文字
通常、パターンは「/」文字で区切られていると考えられますが、
ほぼすべての文字で区切ることができます。 パールレがこれを説明しています。 たとえば、「s///」
上記では区切り文字として中括弧を使用しています。 別の区切り文字を選択すると、引用符を避けることができます。
パターン内の区切り文字:

さ/\/ usr\/地元/\/ usr\/シェア/g; # 区切り文字の選択が間違っています
s#/ usr / local#は、/ usr / share#g; # より良い

論理的にペアになった区切り文字を使用すると、さらに読みやすくなります。

s{/ usr /ローカル/}{は、/ usr / share}g; #まだ良い

アイム 持って トラブル マッチング 他には? より XNUMXつ ライン。 違う?
表示している文字列に (おそらく) 複数の行が含まれていないか、または
それ以外の場合は、パターンで正しい修飾子を使用していません (おそらく)。

複数行のデータを文字列に取り込む方法はたくさんあります。 それが起こってほしいなら
入力の読み取り中に自動的に $/ を設定することをお勧めします (段落や段落の場合はおそらく '' に設定します)
ファイル全体の場合は「undef」)、一度に複数行を読み取ることができます。

"/s" と "/m" (または両方) のどちらを使用するかを決定するには、perlre を読んでください。
「/s」を使用するとドットに改行を含めることができ、「/m」を使用するとキャレットとドルを文字列の隣に一致させることができます。
文字列の末尾だけでなく、改行も必要です。 実際にそうであることを確認する必要があります
そこに複数行の文字列があります。

たとえば、このプログラムは、改行をまたいでいる場合でも、重複した単語を検出します (ただし、
段落のものではありません)。 この例では、ドットを使用していないため、「/s」は必要ありません。
行の境界を越える正規表現。 「/m」も必要ありません。
キャレットやドルがレコード内の改行の隣のどの位置にも一致することは望ましくありません。
ただし、$/ をデフォルト以外に設定することが不可欠です。そうしないと、設定されません。
実際に複数行のレコードを読み込んだことがあります。

$/ = ''; # XNUMX行だけではなく段落全体を読む
while(<>){
while ( /\b([\w'-]+)(\s+\g1)+\b/gi ) { # 単語はアルファベットで始まります
print "$1 を段落 $ で複製します。\n";
}
}

以下は、「From 」で始まる文を検索するコードです (これは、次のように分割されます)
多くのメーラー):

$/ = ''; # XNUMX行だけではなく段落全体を読む
while(<>){
while ( /^From /gm ) { # /m は \n の隣に ^ を一致させます
print "段落$.の先頭から\n";
}
}

段落内の START と END の間のすべてを検索するコードは次のとおりです。

undef $/; # XNUMX 行や段落だけでなく、ファイル全体を読み取る
while(<>){
while ( /START(.*?)END/sgm ) { # /s は . クロスライン境界
"$1\n" を出力します。
}
}

認定条件 できる I プル でる ライン の間に 2 パターン それ   自分自身 on 今とは異なる 線?
Perl の少し変わった「..」演算子を使用できます (perlop に文書化されています)。

perl -ne 'print if /START/ .. /END/' file1 file2 ...

行ではなくテキストが必要な場合は、次を使用します

perl -0777 -ne 'print "$1\n" while /START(.*?)END/gs' file1 file2 ...

ただし、「START」から「END」までを入れ子にしたい場合は、次のような問題が発生します。
バランスの取れたテキストのマッチングに関するこのセクションの質問で説明されている問題。

「..」の別の使用例を次に示します。

while (<>) {
私の $in_header = 1 .. /^$/;
私の $in_body = /^$/ .. eof;
# どちらかを選択してください
} 続く {
$。 = 0 の場合; #$を修正します。
}

認定条件 do I match XML、 HTML、 or 他の 不快な、 醜い 物事   a 正規表現?
正規表現は使用しないでください。 正規表現を忘れてモジュールを使用してください。 の
XML::LibXML、HTML::TokeParser、および HTML::TreeBuilder モジュールは、それぞれが良いスタート地点ではありますが、
名前空間には、特定のタスクやさまざまな方法に特化した他の解析モジュールがあります。
している。 CPAN 検索から開始 (http://metacpan.org/> ) そして、すべての仕事に驚きます
人々はすでにあなたのためにしてくれています! :)

I 置きます a レギュラー 表現 $/ 焙煎が極度に未発達や過発達のコーヒーにて、クロロゲン酸の味わいへの影響は強くなり、金属を思わせる味わいと乾いたマウスフィールを感じさせます。 it しませんでした 作業。 違う?
$/ は文字列である必要があります。 本当にこれを行う必要がある場合は、これらの例を使用できます。

File::Stream がある場合、これは簡単です。

ファイル::ストリームを使用します。

私の $stream = File::Stream->new(
$ファイルハンドル、
区切り文字 => qr/\s*,\s*/,
);

<$stream> 中に "$_\n" を出力します。

File::Stream がない場合は、もう少し作業する必要があります。

sysread の XNUMX つの引数形式を使用すると、バッファに継続的に追加できます。 お先にどうぞ
バッファに追加したら、(正規表現を使用して) 完全な行があるかどうかを確認します。

ローカル $_ = "";
while( sysread FH, $_, 8192, length ) {
while( s/^((?s).*?)your_pattern// ) {
私の $record = $1;
# ここで何かをします。
}
}

次の場合、c フラグと \G アンカーを使用して、foreach と match で同じことを行うことができます。
最後にファイル全体がメモリ内に残っても問題ありません。

ローカル $_ = "";
while( sysread FH, $_, 8192, length ) {
foreach my $record ( m/\G((?s).*?)your_pattern/gc ) {
# ここで何かをします。
}
substr( $_, 0, pos ) = "" if pos;
}

認定条件 do I 代替 大文字と小文字を区別しない on   LHS while 保存する 場合 on   右肩?
これは、Larry Rosler による素敵な Perlish ソリューションです。 ビットごとの XOR のプロパティを利用します。
ASCII 文字列。

$_= "これは TEsT ケースです";

$old = 'テスト';
$new = '成功';

s{(\Q$old\E)}
{ uc $new | (uc $1 ^ $1) 。
(uc(substr $1, -1) ^ substr $1, -1) x
(長さ($new) - 長さ$1)
}エギ;

印刷;

ここでは、上記をモデル化したサブルーチンとして示します。

サブpreserve_case {
私の ($old, $new) = @_;
私の $mask = uc $old ^ $old;

uc $new | $マスク .
substr($mask, -1) x (長さ($new) - 長さ($old))
}

$string = "これは TEsT ケースです";
$string =~ s/(test)/preserve_case($1, "success")/egi;
"$string\n" を出力します。

これは次のように出力します:

これは成功事例です

代わりに、置換単語が長さよりも長い場合は大文字と小文字を区別しません。
オリジナルでは、Jeff Pinyan による次のコードを使用できます。

サブpreserve_case {
私の ($from, $to) = @_;
my ($lf, $lt) = マップの長さ, @_;

if ($lt < $lf) { $from = substr $from, 0, $lt }
else { $from .= substr $to, $lf }

uc $to を返す | ($from ^ uc $from);
}

これにより、文が「this is a SUcCess case」に変わります。

C プログラマーは、必要に応じて、どのプログラミング言語でも C を作成できることを示すためです。
より C に似たソリューションでは、次のスクリプトは置換に同じ大文字と小文字を持たせます。
オリジナルどおり、一文字ずつ。 (また、実行速度が 240% 遅くなります。
Perlish ソリューションが実行されます。) 置換の文字数が文字列よりも多い場合
置換されると、最後の文字の大文字と小文字が残りの置換に使用されます。

# ネイサン・トーキントンによるオリジナル、ジェフリー・フリードルによるマッサージ
#
サブpreserve_case
{
私の ($old, $new) = @_;
私の $state = 0; # 0 = 変化なし。 1 = lc; 2 = UC
my ($i, $oldlen, $newlen, $c) = (0, length($old), length($new));
私の $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;
}
}
# 残りの新しいもので終了します (新しいものが古いものより長い場合用)
if ($newlen > $oldlen) {
if ($state == 1) {
substr($new, $oldlen) = lc(substr($new, $oldlen));
} elsif ($state == 2) {
substr($new, $oldlen) = uc(substr($new, $oldlen));
}
}
$new を返します。
}

認定条件 できる I make 「\w」 match 国民 文字 セット?
「ロケールを使用する」と入力します。 あなたのスクリプトで。 \w 文字クラスは現在のロケールから取得されます。

詳細については、「perllocale」を参照してください。

認定条件 できる I match a ロケールスマート バージョン of 「/[a-zA-Z]/」?
perlre に記載されている POSIX 文字クラス構文「/[[:alpha:]]/」を使用できます。

どのロケールにいても、アルファベット文字は \w の文字です。
数字とアンダースコアなしで。 正規表現としては、「/[^\W\d_]/」のようになります。 これは
補数、つまり非アルファベット文字は、数字と
アンダースコア、または「/[\W\d_]/」。

認定条件 できる I a 変数 〜へ つかいます in a 正規表現?
Perl パーサーは、正規表現内の $variable および @variable 参照を展開します。
ただし、区切り文字が一重引用符でない場合は除きます。 の右辺も覚えておいてください。
「s///」置換は二重引用符で囲まれた文字列とみなされます (詳細については perlop を参照してください)。
また、正規表現の特殊文字は、
\Q に置き換えます。 以下に例を示します。

$string = "プラシド P. オクトパス";
$regex = "P.";

$string =~ s/$regex/Polyp/;
# $string は「ポリパシド P. オクトパス」になりました

なぜなら "。" は正規表現において特別であり、任意の XNUMX 文字と一致します。
正規表現「P.」 ここは一致しました元の文字列で。

「.」の特別な意味をエスケープするには、「\Q」を使用します。

$string = "プラシド P. オクトパス";
$regex = "P.";

$string =~ s/\Q$regex/Polyp/;
# $string は「プラシド ポリープ タコ」になりました

「\Q」を使用すると、正規表現内の <.> が通常の文字として扱われるため、
「P」 「P」の後にドットが続くものと一致します。

この試験は is "/o" 本当に のために?
(ブライアン・ド・フォイによる寄稿)

正規表現の「/o」オプション (perlop および perlreref に文書化されています) は Perl に次のように指示します。
正規表現をコンパイルするのは XNUMX 回だけです。 これは、パターンに
変数。 Perls 5.6 以降では、パターンが変わらない場合、これを自動的に処理します。

一致演算子「m//」、置換演算子「s///」、および通常の
式引用演算子「qr//」は二重引用符構造であり、補間することができます
変数をパターンに組み込みます。 「変数を引用符で囲んで使用するにはどうすればよいですか」に対する回答を参照してください。
正規表現?」の詳細を参照してください。

この例では、引数リストから正規表現を取得し、次の行を出力します。
それに一致する入力:

私の $pattern = シフト @ARGV;

while(<>){
m/$pattern/ の場合に出力します。
}

5.6 より前のバージョンの Perl では、反復ごとに正規表現が再コンパイルされます。
$pattern が変更されていない場合でも。 「/o」は Perl にコンパイルを指示することでこれを防ぎます。
最初にパターンを使用し、それ以降の反復でそれを再利用します。

私の $pattern = シフト @ARGV;

while(<>){
m/$pattern/o の場合は出力します。 # Perl < 5.6 に便利
}

バージョン 5.6 以降では、変数が次の場合、Perl は正規表現を再コンパイルしません。
は変わっていないので、おそらく「/o」オプションは必要ありません。 痛くないけど、それは
どちらも役に立ちません。 任意のバージョンの Perl で正規表現をコンパイルしたい場合
変数が変更された場合でも (つまり、その初期値のみを使用して)、XNUMX 回だけ、
「/o」が必要です。

Perl の正規表現エンジンの動作を観察して、Perl が正しいかどうかを自分で確認できます。
正規表現を再コンパイルします。 「use re 'debug'」プラグマ (Perl 5.005 に付属)
後述)に詳細を示します。 5.6 より前の Perls では、「re」レポートが表示されるはずです。
各反復で正規表現をコンパイルします。 Perl 5.6 以降では、次のようにする必要があります。
最初の反復に関する「再」レポートのみを参照してください。

re 'デバッグ' を使用します。

私の $regex = 'Perl';
foreach ( qw(Perl Java Ruby Python) ) {
STDERR "-" x 73, "\n" を出力します。
print STDERR "$_ を試行しています...\n";
print STDERR "\t$_ は良いです!\n" if m/$regex/;
}

認定条件 do I つかいます a レギュラー 表現 〜へ ストリップ Cスタイル 注釈 from a ファイル?
これは実際に実行できますが、思っているよりもはるかに困難です。 たとえば、これ
一発ギャグ

perl -0777 -pe's {/ \ *。*?\ * /} {} gs 'foo.c

多くの場合に機能しますが、すべての場合に機能するとは限りません。 ご存知のとおり、ある種の人々にとっては単純すぎるのです。
C プログラム、特に引用符で囲まれた文字列内にコメントのように見えるものがあるプログラム。 ために
それは、Jeffrey Friedl によって作成され、後に Fred によって修正された次のようなものが必要です。
カーティス。

$/ = undef;
$_ = <>;
s#/\*[^*]*\*+([^/*][^*]*\*+)*/|("(\\.|[^"\\])*"|'( \\.|[^'\\])*'|.[^/"'\\]*)#define $2 ? $2 : ""#gse;
印刷;

もちろん、これは「/x」修飾子を使用して空白を追加することで、より読みやすく書くこともできます。
とコメント。 ここでは Fred Curtis の厚意により拡張されたものです。

s{
/\* ## /* ... */ コメントの始まり
[^*]*\*+ ## 非 * の後に 1 つ以上の * が続く
(
[^/*][^*]*\*+
)* ## / で始まらない 0 個以上のもの
## ただし末尾は「*」にしてください
/ ## /* ... */ コメントの終わり

| ## またはコメントではないさまざまなもの:

(
" ## " ... " 文字列の始まり
(
\\。 ## エスケープされた文字
| ## また
[^"\\] ## 非 "\
)*
" ## " ... " 文字列の終わり

| ## また

' ## ' ... ' 文字列の開始
(
\\。 ## エスケープされた文字
| ## また
[^'\\] ## 非 '\
)*
' ## ' ... ' 文字列の終わり

| ## また

。 ## その他の文字
[^/"'\\]* ## コメント、文字列、またはエスケープを開始しない文字
)
{$2 を定義しましたか? $2 : ""}gxse;

わずかな変更により、C++ コメントも削除され、場合によっては、
継続文字:

s#/\*[^*]*\*+([^/*][^*]*\*+)*/|//([^\\]|[^\n][\n]? )*?\n|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*) #定義 $3 ? $3 : ""#gse;

できる I つかいます パール レギュラー 表現 〜へ match テキスト?
(ブライアン・ド・フォイによる寄稿)

最初に試すのは、おそらく Perl 標準に含まれる Text::Balanced モジュールです。
Perl 5.8 以降のライブラリ。 複雑なテキストを処理するためのさまざまな機能が備わっています。 の
Regexp::Common モジュールは、使用できる定型パターンを提供することによっても役立ちます。

Perl 5.10 では、再帰を使用してバランスのとれたテキストを正規表現と照合できます。
パターン。 Perl 5.10 より前は、Perl コードを使用するなど、さまざまなトリックに頼る必要がありました。
「(??{})」シーケンス。

以下は再帰正規表現を使用した例です。 目標はすべてをキャプチャすることです
山括弧内のテキスト (ネストされた山括弧内のテキストを含む)。 このサンプルテキストは
には XNUMX つの「メジャー」グループがあります。XNUMX つのレベルのネストを持つグループと XNUMX つのレベルのネストを持つグループです。
巣作り。 山括弧内に合計 XNUMX つのグループがあります。

いくつか持っています> そして
> >
以上です。

バランスの取れたテキストと一致する正規表現では、(Perl 5.10 までの) XNUMX つの新しい正規表現が使用されます。
表現の特徴。 これらは perlre でカバーされており、この例は
そのドキュメントにXNUMXつあります。

まず、新しい所有格「+」を量指定子に追加すると、最長一致が検索され、
後戻りはしない。 山括弧を使用して処理する必要があるため、これは重要です。
バックトラッキングではなく再帰。 グループ "[^<>]++" は XNUMX つ以上の非山括弧を見つけます
後戻りせずに。

XNUMX 番目に、新しい「(?PARNO)」は、指定された特定のキャプチャ グループのサブパターンを参照します。
「パルノ」より。 次の正規表現では、最初のキャプチャ グループが
バランスの取れたテキストであり、最初のバッファ内に同じパターンが必要です。
ネストされたテキスト。 それが再帰的な部分です。 「(?1)」は外側のキャプチャのパターンを使用します。
正規表現の独立した部分としてグループを作成します。

すべてをまとめると、次のようになります。

#!/usr/local/bin/perl5.10.0

私の $string =<<"ここ";
いくつか持っています> そして
> >
以上です。
こちら

私の @groups = $string =~ m/
( # キャプチャ グループ 1 の開始
< # 開始山かっこに一致します
(?:
[^<>]++ # XNUMX つ以上の山かっこ以外、バックトラックなし
|
(?1) # < または > が見つかったので、再帰的にグループ 1 をキャプチャします
)*
> # 右山括弧に一致します
) # キャプチャ グループ 1 の終了
/xg;

$" = "\n\t";
print "見つかりました:\n\t@groups\n";

出力は、Perl が XNUMX つの主要なグループを見つけたことを示しています。

見つかりました:
>
> >

少し追加の作業を行うと、すべてのグループを山かっこで囲むことができます。
他の山かっこでも同様です。 バランスのとれた一致を得るたびに、その外側を削除します
区切り文字 (先ほど一致したものなので、再度一致しないでください) をキューに追加します
処理する文字列の数。 一致するものがなくなるまでこれを続けます。

#!/usr/local/bin/perl5.10.0

私の @queue =<<"HERE";
いくつか持っています> そして
> >
以上です。
こちら

私の $regex = qr/
( # 括弧 1 の始まり
< # 開始山かっこに一致します
(?:
[^<>]++ # XNUMX つ以上の山かっこ以外、バックトラックなし
|
(?1) # 括弧 1 まで再帰
)*
> # 右山括弧に一致します
) # 括弧 1 の終わり
/バツ;

$" = "\n\t";

while( @queue ) {
私の $string = シフト @キュー;

私の @groups = $string =~ m/$regex/g;
@groups の場合は、「見つかった:\n\t@groups\n\n」を出力します。

unshift @queue、map { s/^ $//; $_ } @グループ;
}

出力にはすべてのグループが表示されます。 最も外側の一致が最初に表示され、ネストされた一致が
一致は後で表示されます:

見つかりました:
>
> >

見つかりました:


見つかりました:
>

見つかりました:


この試験は ありません it 意味する それ 正規表現   よく深い? 認定条件 できる I 取得する 周りに それ?
ほとんどの人は、貪欲正規表現が可能な限り一致することを意味します。 技術的に言えば、
実際には、全体ではなく量指定子 (「?」、「*」、「+」、「{}」) が貪欲です。
パターン; Perl は、全体的な貪欲さよりも、局所的な貪欲さと当面の満足感を好みます。 取得するため
同じ量指定子の貪欲でないバージョンには、("??"、"*?"、"+?"、"{}?") を使用します。

例:

my $s1 = my $s2 = "とてもとても寒いです";
$s1 =~ s/ve.*y //; # 私は寒いです
$s2 =~ s/ve.*?y //; # とても寒いです

XNUMX 番目の置換が「y」に遭遇するとすぐに一致を停止することに注目してください。 の
「*?」 quantifier は、正規表現エンジンにできるだけ早く一致を見つけるように効果的に指示します。
できる限り、次の行に制御を渡します。
ホットポテトをプレイしています。

認定条件 do I プロセス 単語 on ライン?
分割機能を使用します。

while (<>) {
foreach my $word (split) {
# ここで $word を使って何かをする
}
}

これは実際には英語の意味での単語ではないことに注意してください。 それは単なる連続した塊です
空白以外の文字。

英数字シーケンス (アンダースコアを含む) のみを操作するには、次のことを検討してください。

while (<>) {
foreach $word (m/(\w+)/g) {
# ここで $word を使って何かをする
}
}

認定条件 できる I 印刷 でる a 単語の頻度 or 回線周波数 まとめ?
これを行うには、入力ストリーム内の各単語を解析する必要があります。 までにそのふりをします
この単語は、非アルファベットではなく、アルファベット、ハイフン、またはアポストロフィの塊を意味します。
前の質問で与えられた単語の空白部分のアイデア:

私の (% 見た);
while (<>) {
while ( /(\b[^\W_\d][\w'-]+\b)/g ) { # 「羊」を見逃します
$seen{$1}++;
}
}

while ( my ($word, $count) = each %seen ) {
print "$count $word\n";
}

行に対して同じことをしたい場合は、正規表現は必要ありません。

私の (% 見た);

while (<>) {
$seen{$_}++;
}

while ( my ($line, $count) = each %seen ) {
print "$count $line";
}

これらの出力をソートされた順序で表示したい場合は、perlfaq4: 「ハッシュをソートするにはどうすればよいですか」を参照してください。
(オプションでキーではなく値によって)?」。

認定条件 できる I do 近似 マッチング?
CPAN から入手可能なモジュール String::About を参照してください。

認定条件 do I 効率良く match 多くの レギュラー 表現 at 一度?
(ブライアン・ド・フォイによる寄稿)

Perl 5.10 以降を使用している場合、これはほとんど簡単です。 あなたはただスマートに対戦するだけです
正規表現オブジェクトの配列:

私の @patterns = ( qr/Fr.d/, qr/B.rn.y/, qr/W.lm./ );

if( $string ~~ @パターン ) {
...
};

スマート マッチは一致するものが見つかると停止するため、すべての式を試す必要はありません。

Perl 5.10 より前のバージョンでは、少し作業する必要があります。 コンパイルを避けたい場合は、
照合するたびに正規表現を使用します。 この例では、perl を再コンパイルする必要があります。
「foreach」ループの反復ごとに正規表現を使用する方法がないため、
$pattern が何になるかを知る:

私の @patterns = qw( foo bar baz );

LINE:ながら( ) {
foreach $pattern ( @patterns ) {
if( /\b$pattern\b/i ) {
印刷;
次のLINE;
}
}
}

「qr//」演算子は perl 5.005 で登場しました。 正規表現はコンパイルされますが、コンパイルされません
それを適用してください。 コンパイル済みバージョンの正規表現を使用すると、perl の動作が少なくなります。 この中で
たとえば、「マップ」を挿入して、各パターンを事前にコンパイルされた形式に変換しました。 残りの
スクリプトは同じですが、より高速です。

私の @patterns = マップ { qr/\b$_\b/i } qw( foo bar baz );

ライン: while( <> ) {
foreach $pattern ( @patterns ) {
if( /$パターン/ ) {
印刷;
次のLINE;
}
}
}

場合によっては、複数のパターンを XNUMX つの正規表現に作成できる場合があります。
ただし、後戻りが必要な状況には注意してください。

my $regex = join '|', qw( foo bar baz );

ライン: while( <> ) {
/\b(?:$regex)\b/i の場合に出力します。
}

正規表現の効率の詳細については、次を参照してください。 マスタリング レギュラー by
ジェフリー・フリードル。 正規表現エンジンがどのように機能するのか、そしてなぜいくつかのパターンがあるのか​​を説明します。
驚くほど非効率的です。 Perl が正規表現を適用する方法を理解したら、
個々の状況に合わせて調整できます。

なぜ しない 単語の境界 検索   "\NS" for 私?
(ブライアン・ド・フォイによる寄稿)

\b が実際に何をするのかを必ず理解してください。これは単語文字 \w と \w の間の境界です。
そして単語の文字ではないもの。 単語の文字ではないものは、
\W ですが、文字列の先頭または末尾にすることもできます。

それは空白と非空白の間の境界ではありません (そうではありません!)、そしてそれは物ではありません
私たちが文章を作るために使う単語の間。

正規表現では、単語の境界 (\b) は「ゼロ幅アサーション」であり、幅がゼロではないことを意味します。
文字列内の文字を表しますが、特定の位置の条件を表します。

正規表現 /\bPerl\b/ の場合、「P」と「P」の前に単語の境界が必要です。
「l」の後に。 「P」の前に単語文字以外の文字がある限り、
「l」に続くと、パターンが一致します。 これらの文字列は /\bPerl\b/ と一致します。

"Perl" # P の前または l の後に char という単語はありません
"Perl " # 前と同じ (スペースは単語文字ではありません)
"'Perl'" # ' 文字は単語文字ではありません
「Perl の」 # P の前に単語の文字はなく、「l」の後に非単語の文字はありません

これらの文字列は /\bPerl\b/ と一致しません。

「Perl_」 # _ は単語の文字です!
"Perler" # P の前に char という単語はありませんが、l の後には XNUMX つあります

ただし、単語を一致させるために \b を使用する必要はありません。 単語以外の文字を検索できます
単語文字で囲まれています。 これらの文字列はパターン /\b'\b/ に一致します。

"don't" # ' 文字は "n" と "t" で囲まれています
"qep'a'" # ' 文字は "p" と "a" で囲まれています

これらの文字列は /\b'\b/ と一致しません。

"foo'" # 非単語の後に単語 char はありません '

\b の補数である \B を使用して、単語が存在しないことを指定することもできます。
境界。

パターン /\Bam\B/ では、「a」の前と「m」の後に単語文字が必要です。
これらのパターンは /\Bam\B/ と一致します。

"llama" # "am" は単語文字で囲まれています
「サミュエル」#同

これらの文字列は /\Bam\B/ と一致しません

"Sam" # "a" の前に単語の境界はありませんが、"m" の後には単語の境界があります
「私はサムです」 # 非単語文字で囲まれた「午前」

なぜ ありません $&、 $`、 or $' 遅く my プログラム ダウン?
(アノ・シーゲル氏による寄稿)

Perl は、プログラム内の任意の場所でこれらの変数のいずれかが必要であることを認識すると、次のように提供します。
それぞれのパターンが一致します。 つまり、すべてのパターンで全体が一致します。
文字列がコピーされ、その一部は $` に、一部は $& に、一部は $' にコピーされます。 したがって、ペナルティは、
長い文字列と頻繁に一致するパターンの場合に最も深刻です。 次の場合は、$&、$'、および $` を避けてください。
使用できますが、使用できない場合は、一度使用したら自由に使用してください。
すでに代金を支払いました。 一部のアルゴリズムはこれらを非常に高く評価していることに注意してください。 現在、
5.005 リリースでは、$& 変数は他の XNUMX つのように「高価」ではなくなりました。

Perl 5.6.1 以降、特殊変数 @- および @+ は $`、$&、および $' を機能的に置き換えることができます。
これらの配列には、各一致の先頭と末尾へのポインタが含まれています (詳細については perlvar を参照してください)。
全文)、基本的に同じ情報が得られますが、次のようなリスクはありません。
過剰な文字列コピー。

Perl 5.10 では、
同じ仕事ですが、全体的なパフォーマンスの低下はありません。 Perl 5.10 はこれらの変数のみを設定します
「/p」修飾子を使用して正規表現をコンパイルまたは実行した場合。

この試験は 良い is 「\G」 in a レギュラー 表現?
「\G」アンカーを使用して、最後に一致した文字列と同じ文字列で次の一致を開始します。
やめた。 正規表現エンジンは、次の文字を検索するために文字をスキップすることはできません。
このアンカーと一致するため、「\G」は文字列アンカーの先頭「^」に似ています。 の
「\G」アンカーは通常、「g」フラグとともに使用されます。 「pos()」の値を
次の試合を開始する位置。 一致演算子が連続して一致を行うと、
最後の一致(または最初の一致)を超えた次の文字の位置で「pos()」を更新します。
見方に応じて、次の一致の文字が変わります)。 それぞれの文字列には、
独自の「pos()」値。

「1122a44」のような文字列内の連続する数字のペアをすべて一致させたいとします。
非数字が見つかった場合は照合を停止します。 11 と 22 を一致させたいのですが、
文字は22 から 44 の間に表示され、「a」で停止したいとします。 単純にペアをマッチングするだけ
桁数は「a」をスキップしても 44 と一致します。

$_ = "1122a44";
私の @pairs = m/(\d\d)/g; # qw( 11 22 44 )

「\G」アンカーを使用すると、22 以降の一致が「a」で始まるように強制されます。 の
正規表現では数字が見つからないため一致できません。そのため、次の一致が行われます。
失敗すると、一致演算子はすでに見つかったペアを返します。

$_ = "1122a44";
私の @pairs = m/\G(\d\d)/g; # qw( 11 22 )

スカラー コンテキストで「\G」アンカーを使用することもできます。 まだ「g」フラグが必要です。

$_ = "1122a44";
while( m/\G(\d\d)/g ) {
「$1 が見つかりました\n」を表示します。
}

文字「a」で一致が失敗すると、perl は「pos()」をリセットし、次の一致を「a」でリセットします。
同じ文字列が先頭から始まります。

$_ = "1122a44";
while( m/\G(\d\d)/g ) {
「$1 が見つかりました\n」を表示します。
}

print "しばらく後に $1 が見つかりました" if m/(\d\d)/g; # 「11」を検索

「c」フラグを使用すると、失敗時の「pos()」リセットを無効にすることができます。これについては perlop と
パールレレフ。 後続の一致は、最後に成功した一致が終了した場所から始まります (
"pos()") は、その間に同じ文字列の一致が失敗した場合でも同様です。 この場合、
"while()" ループが "a" (最後の一致が停止した場所) で開始され、それ以降の一致
アンカーを使用しないので、「a」をスキップして 44 を見つけることができます。

$_ = "1122a44";
while( m/\G(\d\d)/gc ) {
「$1 が見つかりました\n」を表示します。
}

print "しばらく後に $1 が見つかりました" if m/(\d\d)/g; # 「44」を検索

通常、別の一致を試みる場合は、「c」フラグを指定した「\G」アンカーを使用します。
トークナイザーなどで失敗した場合。 Jeffrey Friedl は、次の例を提供しています。
5.004以降。

while (<>) {
ムシャムシャ。
パーサー: {
m/ \G( \d+\b )/gcx && do { print "数値: $1\n"; やり直す; };
m/ \G( \w+ )/gcx && do { print "単語: $1\n"; やり直す; };
m/ \G( \s+ )/gcx && do { print "スペース: $1\n"; やり直す; };
m/ \G( [^\w\d]+ )/gcx && do { print "other: $1\n"; やり直す; };
}
}

各行について、「PARSER」ループは最初に一連の数字の照合を試み、その後に
単語の境界。 この試合は、最後の試合が終了した場所から開始する必要があります (または、
最初に一致した文字列の先頭)。 「m/ \G( \d+\b )/gcx」は「c」フラグを使用しているため、
文字列が正規表現と一致しない場合、perl はリセットされません。 pos()
次の試合は同じ位置から開始して、別のパターンを試します。

です。 パール 正規表現 DFA or NFA? です。 彼ら POSIX 準拠していますか?
Perl の正規表現が DFA (決定論的有限表現) に似ているのは事実ですが、
オートマトン)の egrep(1) プログラム、実際には NFA (非決定的) として実装されます。
有限オートマトン)、バックトラックとバックリファレンスを可能にします。 そしてそれらはPOSIXスタイルではありません
これらはすべてのケースで最悪の動作を保証するためです。 (一部あるようです
たとえ保証されているのが遅さであっても、人々は一貫性の保証を好みます。)
詳細については、Jeffrey Friedl 著『Mastering Regular Expressions』(O'Reilly 刊) を参照してください。
これらの問題について知りたいと願うことはできます (完全な引用は perlfaq2 にあります)。

間違った   grep in a ボイド コンテクスト?
問題は、grep がコンテキストに関係なく戻りリストを構築することです。 これの意味は
Perl にわざわざリストを作成させて、それをただ破棄させることになります。 もしも
リストが大きいと、時間とスペースの両方を無駄にします。 意図が反復処理である場合、
リストを作成し、この目的のために for ループを使用します。

5.8.1 より古い Perl では、マップもこの問題に悩まされます。 しかし、5.8.1 以降、これは
は修正され、マップはコンテキストを認識します。無効なコンテキストでは、リストは構築されません。

認定条件 できる I match ストリング   マルチバイト 文字?
Perl 5.6 以降、Perl はある程度のマルチバイト文字をサポートしています。 Perl 5.8 または
後がおすすめです。 サポートされているマルチバイト文字レパートリーには Unicode が含まれます。
Encode モジュールを介したレガシー エンコーディング。 perluniintro、perlunicode、およびエンコードを参照してください。

古い Perls に行き詰まっている場合は、Unicode::String モジュールを使用して Unicode を実行できます。
Unicode::Map8 および Unicode::Map モジュールを使用した文字変換。 使用している場合
日本語エンコーディングの場合は、jperl 5.005_03 を使用してみてください。

最後に、次の一連のアプローチが Jeffrey Friedl によって提案されました。その記事は、
The Perl Journal の第 5 号では、まさにこの問題について説明しています。

ASCII の大文字のペアが含まれる奇妙な Martian エンコーディングがあると仮定してみましょう。
単一の火星の文字をエンコードします (つまり、XNUMX バイトの「CV」が単一の火星の文字になります。
XNUMX バイトの「SG」、「VS」、「XX」など)。 他のバイトは、次のように単一の文字を表します。
ASCII。

つまり、火星の文字列「私は CVSGXX!」 12 バイトを使用して XNUMX 文字「I」をエンコードします。
「 」、「a」、「m」、「 」、「CV」、「SG」、「XX」、「!」。

ここで、単一文字「/GX/」を検索するとします。 パールは知らない
火星人なので、「I am CVSGXX!」の XNUMX バイトの「GX」が見つかります。 文字列、たとえそれであっても
文字が存在しません。「XX」の隣に「SG」があるため、存在しているように見えますが、
本物の「GX」ではありません。 これは大きな問題です。

これに対処する方法はいくつかありますが、どれも面倒です。

# 隣接する「martian」バイトが隣接していないことを確認します。
$martian =~ s/([AZ][AZ])/ $1 /g;

$martian =~ /GX/; の場合、「GX が見つかりました!\n」と表示します。

またはこのように:

私の @chars = $martian =~ m/([AZ][AZ]|[^AZ])/g;
# 上記は概念的に次と似ています: my @chars = $text =~ m/(.)/g;
#
foreach my $char (@chars) {
print "GX が見つかりました!\n", last if $char eq 'GX';
}

またはこのように:

while ($martian =~ m/\G([AZ][AZ]|.)/gs) { # \G おそらく不要
if ($1 eq 'GX') {
「GX を見つけました!\n」を表示します。
最終;
}
}

ここでは、Benjamin Goldberg による、少し痛みの少ない別の方法を紹介します。
幅ゼロの否定後読みアサーション。

$martian =~ m/ の場合、「GX が見つかりました!\n」と表示します
(?
(?:[AZ][AZ])*?
GX
/バツ;

これは、「火星」文字 GX が文字列内にある場合は成功しますが、それ以外の場合は失敗します。 もし、あんたが
(?) を使用するのは好きではありません。
(?

$-[0] と $+[0] に間違ったものを入れてしまうという欠点がありますが、これは通常
回避できます。

認定条件 do I match a レギュラー 表現 in a 変数?
(ブライアン・ド・フォイによる寄稿)

一致演算子 (またはその他の機能するもの) にパターンをハードコーディングする必要はありません。
正規表現を使用します)。 後で使用するためにパターンを変数に入れることができます。

一致演算子は二重引用符のコンテキストなので、変数を補間することができます。
二重引用符で囲まれた文字列のようなものです。 この場合、正規表現をユーザー入力として読み取ります。
それを $regex に保存します。 $regex にパターンを取得したら、その変数を
一致演算子。

chomp( 私の $regex = );

if( $string =~ m/$regex/ ) { ... }

$regex 内の正規表現特殊文字はすべて特殊文字であり、パターンは
まだ有効でなければなりません。そうしないと Perl が文句を言います。 たとえば、このパターンでは、
対になっていない括弧。

my $regex = "一致しない (括弧";

"すべてをバインドする XNUMX つの括弧" =~ m/$regex/;

Perl が正規表現をコンパイルするとき、括弧は正規表現の始まりとして扱われます。
記憶の一致。 右括弧が見つからない場合は、次のようにエラーが表示されます。

Unmatched ( 正規表現; スクリプト行 3 で <-- HERE in m/Unmatched ( <-- HERE paren/ でマークされています。

状況に応じて、いくつかの方法でこれを回避できます。 まず、そうでない場合は、
文字列内の文字を特別なものにしたい場合は、次のようにエスケープできます。
文字列を使用する前に「quotemeta」を付けてください。

chomp( 私の $regex = );
$regex = quotemeta( $regex );

if( $string =~ m/$regex/ ) { ... }

「\Q」および「\E」シーケンスを使用して、一致演算子でこれを直接行うこともできます。 の
「\Q」は Perl に特殊文字のエスケープを開始する場所を指示し、「\E」はどこからエスケープするかを指示します。
停止します (詳細については perlop を参照してください)。

chomp( 私の $regex = );

if( $string =~ m/\Q$regex\E/ ) { ... }

あるいは、正規表現の引用演算子である「qr//」を使用することもできます (詳細については perlop を参照してください)。
詳細)。 パターンを引用し、場合によってはコンパイルし、通常のパターンを適用できます。
式フラグをパターンに設定します。

chomp( 私の $input = );

私の $regex = qr/$input/is;

$string =~ m/$regex/ # m/$input/is と同じ;

全体を「eval」ブロックで囲んでエラーをトラップすることもできます。

chomp( 私の $input = );

評価{
if( $string =~ m/\Q$input\E/ ) { ... }
};
$@ の場合は $@ に警告します。

または...

私の $regex = eval { qr/$input/is };
if( 定義された $regex ) {
$string =~ m/$regex/;
}
他{
$@ に警告します。
}

著者 そして COPYRIGHT


Copyright(c)1997-2010 Tom Christiansen、Nathan Torkington、およびその他の著者。
All rights reserved.

このドキュメントは無料です。 同じ条件で再配布および/または変更できます
Perl自体として。

配布に関係なく、このファイルのすべてのコード例はここに配置されます
パブリックドメイン。 あなたはあなた自身のプログラムでこのコードを使用することを許可され、奨励されています
あなたが適切だと思うように、楽しみのために、または利益のために。 クレジットを与えるコードの簡単なコメントは
礼儀正しく、必須ではありません。

onworks.netサービスを使用してperlfaq6をオンラインで使用する


無料のサーバーとワークステーション

Windows と Linux のアプリをダウンロード

Linuxコマンド

Ad