English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

正規表現の零幅断言の詳細

正規表現零幅断言:

零幅断言は正規表現の難点であり、この章では特にマッチング原理の面から分析します。零幅断言には他にも「環視」や「予検索」などと呼ばれる名前がありますが、これらは私たちの焦点ではありません。

一.基本概念:

零幅断言はその名の通り、零幅のマッチングであり、マッチングした内容はマッチング結果に保存されません。最終的なマッチング結果は単に位置だけです。
役割は、指定された位置に限定条件を追加し、その位置の前後の文字が限定条件を満たす必要があることを規定することで、正規表現の文字列マッチングが成功するようにします。
注意:ここで言う子表現は小括弧で括られた表現だけではなく、正規表現の任意のマッチングユニットを指します。
javascriptは零幅先行断言をサポートしていますが、零幅先行断言は正規表現の正規先行断言と正規後行断言に分類されます。

.負向零幅アンチャー:

実例コード一:

コード例として以下の通りです:863ab
";/var reg=63;=[A-ab(&#/;
g;

以上のコードでは、正規表現の意味は「大文字の後ろに続く文字列「ab」をマッチングする」ということです。最終的なマッチング結果は「ab」で、零幅アンチャー「(?=[A-Z])"は何もマッチングしません。これは、この位置の後ろに大文字が続く必要があることを規定するだけです。

実例コード二:

コード例として以下の通りです:863ab
";/var reg=63;![A-ab(&#/;
g;

以上のコードでは、正規表現の意味は「大文字の後ろに続かない文字列「ab」をマッチングする」ということです。正規表現は何もマッチングしませんでした。なぜなら、文字列では「ab」の後ろに大文字があるからです。

二.マッチング原理:

上記のコードは、零幅アンチャーがどのようにマッチングするかについて概念として説明しています。
以下では、正規零幅アンチャーがどのようにマッチングするかについて、マッチング原理の方法で説明します。
1.正向零幅アンチャー:
.負向零幅アンチャー:

var str="<div>antzone";
";/^(?=<)<[^>]+>\w+/;
g;

console.log(str.match(reg));
まず、正則表現の"^"が制御権を取得し、位置0からマッチングを開始し、始めの位置0をマッチングし成功し、制御権を"(?=<)"、"^"は零幅であるため、"(?=<)"、"^"は零幅であるため、"(?=<)"も位置0からマッチングを開始し、その位置の右側が文字"<"であることを要求します。位置0の右側が文字"<"であるため、マッチングが成功し、制御権が"<"に移行します。しかし、"(&#

2;=<)"も零幅であり、したがって位置0からマッチングを開始し、マッチングが成功しました。後のマッチングプロセスについては説明しません。

.負向零幅アンチャー:

コード例として以下の通りです:863var str="abZW88ab 
";/var reg=63;![A-ab(&#/Z]) 
g;

console.log(str.match(reg));
マッチングプロセスは以下の通りです:1まず、正則表現の文字"a"が制御権を取得し、位置0からマッチングを開始し、文字"a"をマッチングし成功し、制御権を"b"に移行し、位置63;![A-Z])"から位置2位置からマッチングを開始し、文字"b"をマッチングし成功し、制御権を"(位置からマッチングを開始し、その位置の右側が任意の大文字でないことを要求します。位置の右側が大文字"Z"であるため、マッチングが失敗し、制御権が再び文字"a"に戻され、位置2位置から試行マッチングを開始し、マッチングが失敗し、制御権が再び文字"a"に戻され、位置7位置から試行マッチングを開始し、マッチングが成功し、制御権を"b"に移行し、位置8位置から試行マッチングを開始し、マッチングが成功した後、制御権を"(?![A-Z])"から位置9位置から試行マッチングを開始し、その位置の右側が大文字でないことを規定します。マッチングが成功しましたが、実際には文字をマッチングしません。したがって、最終的なマッチング結果は"ab"です。

以下に追加します

零幅アンチャーは、正則表現の一つの方法であり、正則表現はコンピュータサイエンスにおいて、特定の文法規則に従う文字列の集合を記述またはマッチングするための単一の文字列を指します。

定義と解説

零幅アンチャーは、正則表現の方法の一つです
正則表現は、コンピュータサイエンスにおいて、特定の文法規則に従う文字列の集合を記述またはマッチングするための単一の文字列を指します。多くのテキストエディタや他のツールでは、正則表現が検索や/または、特定のパターンに一致するテキスト内容を置き換えるために使用されます。多くのプログラミング言語は、正規表現を使用して文字列操作を実行する機能をサポートしています。例えば、Perlには強力な正規表現エンジンが内蔵されています。正規表現の概念は、Unixのツールソフトウェア(例えばsedやgrep)で普及しました。正規表現は通常「regex」と略され、単数形はregexp、regex、複数形はregexps、regexes、regexenと呼ばれます。

零幅断言

特定の内容の前にまたは後に何かを検索するために使用されます。これは\b、^、$のように位置を指定するために使用されるため、この位置が特定の条件(断言)を満たすべきであるという意味があり、したがってこれらは零幅断言とも呼ばれます。具体的な例を示すのが最善です:断言はある事実が真であることを宣言するために使用されます。正規表現では、断言が真である場合にのみマッチが続行されます。

(?=exp)は零幅正预测先行断言とも呼ばれ、自身が現れる位置の後がexpにマッチすることを断言します。例えば\b(?=re)\w+\bはreで始まる単語の後半部分(re以外の部分)をマッチします(例えばreading a book.の場合、adingをマッチします)。

var reg = new Regex(@"\w+(?=ing)");
var str = "muing";
Console.WriteLine(reg.Match(str).Value);//muが返されます

(?<=exp)は零幅正回顾後発断言とも呼ばれ、自身が現れる位置の前がexpにマッチすることを断言します。例えば\b\w+(?<=ing\b)はingで終わる単語の前半部分(ing以外の部分)をマッチします(例えばI am reading.の場合、readをマッチします)。

假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了),你可以这样查找需要在前面和里面添加逗号的部分:((?=\d)\d{3}+\b、それを使って1234567890を検索すると、結果は234567890。
以下の例では、これらの断言の両方を使用しています:(?<=\s)\d+(?=\s) 空白文字で区切られた数字に一致します(再び強調しますが、これらの空白文字を含まないことを確認してください)。

ネガティブゼロ幅断言

前に述べたように、特定の文字や文字クラスに属していない文字を検索する方法(反対の意味)について言及しました。しかし、特定の文字が存在しないことを確認したいが、マッチする必要がない場合はどうすればよいでしょうか?例えば、以下のような単語を検索する場合--そこにアルファベットqが現れましたが、その後はuでないアルファベットが続くので、以下のように試してみましょう:

\b\w*q[^u]\w*\bは後続がuでないアルファベットqを含む単語をマッチします。しかし、さらにテストを多く行う(または、十分に鋭い思考で直接観察できた場合)、qが単語の末尾に現れる場合(例えばIraq、Benq)、この式は誤りになります。これは[^u]は常に1文字をマッチするため、qが単語の最後の文字の場合、後続の[^u]はqの後の単語区切り(スペース、ピリオドや他の何か)をマッチし、後続の\w*\bは次の単語をマッチしますので、\b\w*q[^u]\w*文字全体をIraq fightingと一致させる。ネガティブゼロ幅断言はこのような問題を解決できるため、場所を1つだけマッチし、どんな文字も消費しない。今やこの問題を解決する方法はこうである:\b\w*q(?!u)\w*\b。

零宽度負预测先行断言(?!exp),この位置の後に一致する表达式expが存在しないことを断言します。例えば:\d{3})(?!\d)は三位数をマッチングし、その後は数字ではありません;\b((?!abc)\w)+\bは連続した文字列abcを含まない単語をマッチングします。
同様に、(?<!exp),零宽度負回顾后发断言を使って、この位置の前に一致する表达式expが存在しないことを断言します:(?<![a-z])\d{7}は前の文字が小文字でない七桁の数字をマッチングします。

より複雑な例:(?<=<(\w+)>).*(?=<\/\1>)は属性を含まない簡単なHTMLタグ内の内容をマッチングします。(<?=(\w+)>)が指定されています:括弧で囲まれた単語(例えば<b>が可能性があります)が前缀、その後は.*(任意の文字列),最後に前缀(\63;=<\/\1>)。注意、接尾辞の\/、それは前述のエスケープシーケンスを使用しています;\1は逆引用であり、最初にキャプチャしたグループを参照しています;\(\w+)内の内容をマッチングします。この場合、接頭辞が実際には<b>の場合、接尾辞は<になります。/b>が終わるまでの全体をマッチングします。/b>間の内容(再び強調しますが、接頭辞や接尾辞自体は含まれません)。

上記の内容は少し難しいですね。補足を少し紹介しましょう。

断言はあるべき事実を宣言するために使用されます。正規表現では、断言が真である場合にのみマッチングが続行されます。
次の四つは特定の内容(これらの内容を含まない)の前にまたは後に何かを検索するために使用されます、つまりこれらは\b、^、$のように位置を指定するものであり、その位置は特定の条件(即ち断言)を満たすべきですから、これらも零宽度断言と呼ばれます。例を示すのが一番良いでしょう:

(?=exp)も零宽度正预测先行断言と呼ばれ、自身の位置の後に一致する表达式expが存在することを断言します。例えば\b\w+(?=ing\b),「ing」で終わる単語の前半部分(「ing」以外の部分)を一致させる、例えば「I'm singing while you're dancing.」を検索すると「sing」と「danc」が一致します。
(?<=exp)も零宽度正回顾后发断言と呼ばれ、自身の位置の前に一致する表达式expが存在することを断言します。例えば(?<=\bre)\w+「re」で始まる単語の後半部分(「re」以外の部分)を一致させる、例えば「reading a book」を検索すると「ading」が一致します。

假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了),你可以这样查找需要在前面和里面添加逗号的部分:((?<=\d)\d{3}*\b、それを使って1234567890を検索すると、結果は234567890。
以下の例では、これらの断言の両方を使用しています:(?<=\s)\d+(?=\s) 空白文字で区切られた数字に一致します(再び強調しますが、これらの空白文字を含まないことを確認してください)。

補足二:

最近、htmlファイルのソースコード処理を行うために、正規表現の検索および置換が必要でした。この機会を利用して、正規表現を系統的に学びました。以前にも正規表現を使っていましたが、いつも一時的に学んで通り越していました。学習の過程で多くの問題に直面しましたが、特に零幅正先行断言(ここでまた、ネット上にはどこでもコピーと貼り付けの内容が溢れています。問題に直面して、多くの重複する情報を確認しました。汗!!!)特に困難でしたので、ここに自分の理解をまとめ、以後の参照のために記録しました。

      零幅正先行断言とは何か、msdnの公式の定義を見てみましょう

(?= 括弧内の表現)

(零幅正先行断言です。)子表現がこの位置の右側に一致した場合のみ、一致を続けます。例えば、\w+(?=\d) 数字に続く単語と一致させますが、数字と一致しません。

      典型的な例:ある単語がingで終わる場合、ingの前の内容を取得する必要があります

var reg = new Regex(@"\w+(?=ing)");
var str = "muing";
Console.WriteLine(reg.Match(str).Value);//muが返されます

      これはどこでも見られる例ですが、ここまで来て、実際にはexpの表現の前の内容が返されるということがわかったかもしれません。

     以下ののコードを見てみましょう

var reg = new Regex(@"a(?=b)c");
var str = "abc";
Console.WriteLine(reg.IsMatch(str));//falseが返されます

      なぜfalseが返されるのでしょうか?

     実際にはmsdnの公式の定義は言われていますが、ただ公式的に言っているだけです。ここで注意すべき重要なポイントは、この位置です。もちろん、位置ではなく文字ではありません。それで公式の定義と最初の例を結び付けながら、二つ目の例を理解しましょう:

     aの後がbであるため、その時一致内容a(最初の例からわかるように、expの一致内容を返さず、aのみを返します)が返されました。その時a(?=b)cの中のa(?部分已经解决了,接下来要解決cの一致問題を,その時一致させるcは文字列abcのどこから始まるのか,公式の定義を結び付けると,子表現の位置から右に始まるのがわかります。したがって、bの位置から始まるわけですが、bはa(&# に一致しません。63;=b)cの残りのc、したがってabcはa(?=b)c了。

     それでは、上記のものをマッチさせるために正規表現はどう書けばいいですか?

     答えは:a(?=b)bc

     もちろん、直接abcでマッチするとか言う人もいますが、こんな手間をかけなくてもいいんじゃないですか?もちろんそんな手間はかけません、ただ零幅正向先行断言がどのようなことか説明するためです。他の零幅断言も同じ原理です!

補足三

(?=exp):零幅正向先行断言、自身の出現位置の後ろにマッチする表現expを断言。

#_path後のものがproduct
  'product_path'.scan /(product)(?=_path)/

(?<=exp):零幅正向後向き断言、自身の出現位置の前にマッチする表現expを断言

#name:前のものがname:で結果がwangfei
'name:wangfei'.scan /(?<=name:)(wangfei)/ #wangfei

(?!exp):零幅負向先行断言、この位置の後ろにマッチしない表現expを断言。

#_path後のものにマッチしない
'product_path'.scan /(product)(?!_path)/  #nil
#_url後のものにマッチしない
'product_path'.scan /(product)(?!_url)/  #product

(?<!exp):零幅負向後向き断言、この位置の前にマッチしない表現expを断言

#name:前のものにマッチしない
'name:angelica'.scan /(?<!name:)(angelica)/  #nil
#nick_name:前のものにマッチしない
'name:angelica'.scan /(?<!nick_name:)(angelica)/#angelica

編集者もこれに疲れました、良いものがあればまた共有します、今日はシャワーを浴びて寝ます

おすすめ