単語を含まない行に一致する正規表現
-
03-07-2019 - |
質問
他のツール (例: grep -v
)。しかし、特定の単語を含まない行を照合することは可能でしょうか。 hede
, 、正規表現を使用しますか?
入力:
hoho
hihi
haha
hede
コード:
grep "<Regex for 'doesn't contain hede'>" input
望ましい出力:
hoho
hihi
haha
解決
正規表現が逆マッチングをサポートしないという概念は完全に真実ではありません。ネガティブなルックアラウンドを使用して、この動作を模倣できます。
^((?!hede).)*$
上記の正規表現は、(サブ)文字列「hede」を含まない の文字列、または改行なしの行に一致します。前述のように、これは正規表現が<!> quot; good <!> quot;であるものではありません。で(またはそうすべきです)、それでも 可能です。
また、改行文字も一致させる必要がある場合は、 DOT-ALL修飾子(次のパターンの末尾のs
):
/^((?!hede).)*$/s
またはインラインで使用:
/(?s)^((?!hede).)*$/
(/.../
は正規表現の区切り文字、つまりパターンの一部ではない)
DOT-ALL修飾子が使用できない場合、文字クラス[\s\S]
で同じ動作を模倣できます:
/^((?!hede)[\s\S])*$/
説明
文字列は、単にn
文字のリストです。各文字の前後には、空の文字列があります。したがって、n+1
文字のリストには"ABhedeCD"
空の文字列が含まれます。文字列e
:
┌──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┐
S = │e1│ A │e2│ B │e3│ h │e4│ e │e5│ d │e6│ e │e7│ C │e8│ D │e9│
└──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┘
index 0 1 2 3 4 5 6 7
(?!hede).
は空の文字列です。正規表現"hede"
は先読みして、表示するサブストリング.
がないかどうかを確認します。そうでない場合(他の何かが表示される場合)、((?!hede).)*
(ドット)は改行以外の任意の文字に一致します。ルックアラウンドは、文字を消費しないため、ゼロ幅アサーションとも呼ばれます。彼らは何かを主張/検証するだけです。
したがって、私の例では、文字が^((?!hede).)*$
(ドット)で消費される前に、空の文字列がすべて先にe3
がないかどうかを確認するために最初に検証されます。正規表現(?!hede)
はそれを1回だけ行うため、グループにラップされ、ゼロ回以上繰り返されます:<=>。最後に、入力全体が消費されるように、入力の開始と終了が固定されています:<=>
ご覧のとおり、入力<=>は失敗します。これは、<=>で正規表現<=>が失敗するためです(は <=>前にあります!)。
他のヒント
の解決策はで始まるではないことに注意してください<!>#8220; hede <!>#8221; :
^(?!hede).*$
は一般に、含まない <!>#8220; hede <!>#8221; の解決策よりもはるかに効率的です:
^((?!hede).)*$
前者は<!>#8220; hede <!>#8221;をチェックします。すべての位置ではなく、入力文字列<!>#8217;の最初の位置のみ。
grepに使用している場合は、grep -v hede
を使用してhedeを含まないすべての行を取得できます。
ETAああ、質問を読み直すと、grep -v
はおそらく<!> quot; tools options <!> quot;が意味するものです。
回答:
^((?!hede).)*$
説明:
^
文字列の始まり、
(
グループ化して\ 1にキャプチャ(0回以上(可能な限り多くの量に一致))、
(?!
存在しないかどうかを確認してください
hede
文字列、
)
先読みの終わり、
.
\ n以外の任意の文字、
)*
\ 1の終わり(注:このキャプチャで数量詞を使用しているため、キャプチャされたパターンの最後の繰り返しのみが\ 1に格納されます)
$
オプションの\ nの前、および文字列の終わり
与えられた答えはまったく問題ありませんが、学術的なポイントです:
理論的なコンピューターサイエンスの意味での正規表現は、使えないこのようになります。彼らにとっては、次のようなものでなければなりませんでした:
^([^h].*$)|(h([^e].*$|$))|(he([^h].*$|$))|(heh([^e].*$|$))|(hehe.+$)
これは完全一致のみを行います。サブマッチでそれを行うのはさらに厄介です。
文字列全体が一致した場合に正規表現テストをのみ失敗させる場合、次のように動作します:
^(?!hede$).*
e.g。 -<!> quot; foo <!> quot以外のすべての値を許可する場合(つまり、<!> quot; foofoo <!> quot;、<!> quot; barfoo <!> quot ;、および<!> quot; foobar <!> quot;はパスしますが、<!> quot; foo <! > quot;失敗します)、使用:^(?!foo$).*
もちろん、 exact の等価性をチェックする場合、この場合のより一般的な解決策は、文字列の等価性をチェックすることです。つまり、
myStr !== 'foo'
正規表現機能が必要な場合は、テストの否定 を行うこともできます(ここでは、大文字と小文字の区別と範囲の一致):
!/^[a-f]oo$/i.test(myStr)
この回答の先頭にある正規表現ソリューションは、肯定的な正規表現テストが必要な場合(おそらくAPIによって)に役立つ場合があります。
FWIW、正規言語(有理言語)は補完の下で閉じられているため、別の表現を否定する正規表現(有理表現)を見つけることは常に可能です。ただし、これを実装するツールは多くありません。
Vcsn は、この演算子をサポートします(これは{c}
、postfixを示します) )。
最初に式のタイプを定義します:ラベルは、たとえばlal_char
からa
までを選択する文字(z
)です(もちろん、補完を使用するときはアルファベットを定義することが非常に重要です)。 <!> quot; value <!> quot;各単語に対して計算されるのは、単なるブール値です。true
単語は受け入れられ、false
、拒否されます。
Pythonの場合:
In [5]: import vcsn
c = vcsn.context('lal_char(a-z), b')
c
Out[5]: {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z} → 𝔹
その後、式を入力します:
In [6]: e = c.expression('(hede){c}'); e
Out[6]: (hede)^c
この式をオートマトンに変換します:
In [7]: a = e.automaton(); a
最後に、このオートマトンを単純な式に変換します。
In [8]: print(a.expression())
\e+h(\e+e(\e+d))+([^h]+h([^e]+e([^d]+d([^e]+e[^]))))[^]*
+
は通常|
、\e
は空の単語、[^]
は通常.
(任意の文字)と表記されます。したがって、少し書き換えて()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).*
。
この例は、
ここに良い説明があります。これは、why意的な正規表現を否定することが容易ではない理由です。ただし、他の答えに同意する必要があります。これが仮説的な質問以外の場合、正規表現はここでは正しい選択ではありません。
負の先読みを使用すると、正規表現は特定のパターンを含まないものに一致します。これはBart Kiersによって回答され説明されます。素晴らしい説明!
ただし、Bart Kiersの回答では、lookaheadパーツは1文字から4文字先をテストしながら、任意の1文字と一致します。これを回避し、先読み部分にテキスト全体をチェックアウトさせ、「ヘデ」がないことを確認してから、通常の部分(。*)がテキスト全体を一度にすべて食べられるようにすることができます。
改良された正規表現は次のとおりです。
/^(?!.*?hede).*$/
負の先読み部分の(*?)遅延量指定子はオプションです。データに応じて、代わりに(*)貪欲量指定子を使用できます。「hede」が存在し、テキストの前半にある場合、遅延量指定子はより高速になります。それ以外の場合、貪欲な量指定子は高速になります。ただし、「hede」が存在しない場合は、両方とも同等に遅くなります。
デモコードです。
lookaheadの詳細については、次のすばらしい記事をご覧ください: LookaheadとLookbehindの習得。
>また、 RegexGen.js もご覧ください。これは、複雑な正規表現の作成を支援するJavaScript正規表現ジェネレーターです。 RegexGen.jsを使用すると、より読みやすい方法で正規表現を構築できます。
var _ = regexGen;
var regex = _(
_.startOfLine(),
_.anything().notContains( // match anything that not contains:
_.anything().lazy(), 'hede' // zero or more chars that followed by 'hede',
// i.e., anything contains 'hede'
),
_.endOfLine()
);
ベンチマーク
提示されたオプションのいくつかを評価し、それらのパフォーマンスを比較し、いくつかの新しい機能を使用することにしました。 .NET Regexエンジンのベンチマーク: http://regexhero.net/tester/
ベンチマークテキスト:
検索された式が含まれているため、最初の7行は一致しないはずですが、下の7行は一致するはずです!
Regex Hero is a real-time online Silverlight Regular Expression Tester.
XRegex Hero is a real-time online Silverlight Regular Expression Tester.
Regex HeroRegex HeroRegex HeroRegex HeroRegex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her Regex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her is a real-time online Silverlight Regular Expression Tester.Regex Hero
egex Hero egex Hero egex Hero egex Hero egex Hero egex Hero Regex Hero is a real-time online Silverlight Regular Expression Tester.
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRegex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her
egex Hero
egex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her is a real-time online Silverlight Regular Expression Tester.
Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her is a real-time online Silverlight Regular Expression Tester.
Nobody is a real-time online Silverlight Regular Expression Tester.
Regex Her o egex Hero Regex Hero Reg ex Hero is a real-time online Silverlight Regular Expression Tester.
結果:
結果は、3回の実行の中央値としての1秒あたりの反復数です-大きい数=良い
01: ^((?!Regex Hero).)*$ 3.914 // Accepted Answer
02: ^(?:(?!Regex Hero).)*$ 5.034 // With Non-Capturing group
03: ^(?>[^R]+|R(?!egex Hero))*$ 6.137 // Lookahead only on the right first letter
04: ^(?>(?:.*?Regex Hero)?)^.*$ 7.426 // Match the word and check if you're still at linestart
05: ^(?(?=.*?Regex Hero)(?#fail)|.*)$ 7.371 // Logic Branch: Find Regex Hero? match nothing, else anything
P1: ^(?(?=.*?Regex Hero)(*FAIL)|(*ACCEPT)) ????? // Logic Branch in Perl - Quick FAIL
P2: .*?Regex Hero(*COMMIT)(*FAIL)|(*ACCEPT) ????? // Direct COMMIT & FAIL in Perl
.NETはアクション動詞(* FAILなど)をサポートしていないため、ソリューションP1およびP2をテストできませんでした
概要:
提案されたほとんどのソリューションをテストしようとしましたが、特定の単語に対していくつかの最適化が可能です。
たとえば、検索文字列の最初の2文字が同じでない場合、回答03は次のように展開できます。
^(?>[^R]+|R+(?!egex Hero))*$
わずかなパフォーマンスの向上をもたらします。
しかし、全体的に最も読みやすく、パフォーマンス面で最速のソリューションは、条件ステートメントを使用して05のようです または04所有数量詞を使用します。 Perlソリューションはさらに高速で読みやすいものにすべきだと思います。
正規表現ではありませんが、パイプを使用してシリアルグレップを使用してノイズを除去することは論理的で便利であることがわかりました。
eg。コメントなしでApache設定ファイルを検索します-
grep -v '\#' /opt/lampp/etc/httpd.conf # this gives all the non-comment lines
and
grep -v '\#' /opt/lampp/etc/httpd.conf | grep -i dir
シリアルgrepのロジックは(コメントではなく)および(dirに一致)です
これにより、各ポジションで先読みをテストすることを避けます:
/^(?:[^h]+|h++(?!ede))*+$/
(。netの場合)と同等:
^(?>(?:[^h]+|h+(?!ede))*)$
旧回答:
/^(?>[^h]+|h+(?!ede))*$/
前述の(?:(?!hede).)*
は固定できるので素晴らしい。
^(?:(?!hede).)*$ # A line without hede
foo(?:(?!hede).)*bar # foo followed by bar, without hede between them
ただし、この場合は次で十分です。
^(?!.*hede) # A line without hede
この簡略化により、<!> quot; AND <!> quot;追加された条項:
^(?!.*hede)(?=.*foo)(?=.*bar) # A line with foo and bar, but without hede
^(?!.*hede)(?=.*foo).*bar # Same
次のようにします:
^[^h]*(h(?!ede)[^h]*)*$
他の回答よりも正確で効率的。 Friedlの <!> quot; unrolling-the-loop <!> quot; 効率化手法を実装し、バックトラッキングの必要性を大幅に減らします。
否定文字クラスに似た単語を否定するために文字を照合する場合:
たとえば、文字列:
<?
$str="aaa bbb4 aaa bbb7";
?>
使用しないでください:
<?
preg_match('/aaa[^bbb]+?bbb7/s', $str, $matches);
?>
使用:
<?
preg_match('/aaa(?:(?!bbb).)+?bbb7/s', $str, $matches);
?>
通知"(?!bbb)."
は後読みでも先読みでもありません。たとえば、lookcurrentです。
"(?=abc)abcde", "(?!abc)abcde"
OPは指定していないか、または 鬼ごっこ 正規表現が使用されるコンテキスト (プログラミング言語、エディタ、ツール) を示すポスト。
私の場合、ファイルの編集中にこれを行う必要があることがあります。 Textpad
.
Textpad
は一部の正規表現をサポートしていますが、先読みや後読みはサポートしていないため、いくつかの手順が必要です。
すべての行を保持したい場合は、 しないでください 文字列を含む hede
, 、私なら次のようにします。
1.ファイル全体を検索/置換して、テキストを含む各行の先頭に一意の「タグ」を追加します。
Search string:^(.)
Replace string:<@#-unique-#@>\1
Replace-all
2.文字列を含むすべての行を削除します
hede
(置換文字列は空です):
Search string:<@#-unique-#@>.*hede.*\n
Replace string:<nothing>
Replace-all
3.この時点で、残りの行はすべて しないでください 文字列を含む
hede
. 。すべての行から一意の「タグ」を削除します (置換文字列は空です)。
Search string:<@#-unique-#@>
Replace string:<nothing>
Replace-all
これで、文字列を含むすべての行を含む元のテキストが得られます。 hede
削除されました。
私が探しているなら 何か他のことをする 以下の行のみに しないでください 文字列を含む hede
, 、私なら次のようにします。
1.ファイル全体を検索/置換して、テキストを含む各行の先頭に一意の「タグ」を追加します。
Search string:^(.)
Replace string:<@#-unique-#@>\1
Replace-all
2.文字列を含むすべての行について
hede
, 、一意の「タグ」を削除します。
Search string:<@#-unique-#@>(.*hede)
Replace string:\1
Replace-all
3.この時点で、一意の「タグ」で始まるすべての行が、 しないでください 文字列を含む
hede
. 。私は今、自分のことができるようになりました 何か他のもの それらの行のみに。
4.完了したら、すべての行から一意の「タグ」を削除します (置換文字列は空です)。
Search string:<@#-unique-#@>
Replace string:<nothing>
Replace-all
私の意見では、トップアンサーのより読みやすいバリアント:
^(?!.*hede)
基本的に、<!> quot;「hede」が含まれていない場合にのみ、行の先頭で一致します<!> quot; -したがって、要件はほぼ直接正規表現に翻訳されました。
もちろん、複数の障害要件を持つことが可能です:
^(?!.*(hede|hodo|hada))
詳細: ^アンカーは、正規表現エンジンがすべての文字列と一致する文字列内のすべての場所で一致を再試行しないようにします。
先頭の^アンカーは、行の先頭を表すためのものです。 grepツールは、各行を一度に1つずつ照合します。複数行の文字列を使用しているコンテキストでは、<!> quot; m <!> quot;を使用できます。フラグ:
/^(?!.*hede)/m # JavaScript syntax
または
(?m)^(?!.*hede) # Inline flag
Ruby-2.4.1 の導入以来、新しいものを使用できるようになりました。 オペレーター不在 Rubyの正規表現では
公式からの 博士
(?~abc) matches: "", "ab", "aab", "cccc", etc.
It doesn't match: "abc", "aabc", "ccccabc", etc.
したがって、あなたの場合、 ^(?~hede)$
あなたの代わりに仕事をしてくれます
2.4.1 :016 > ["hoho", "hihi", "haha", "hede"].select{|s| /^(?~hede)$/.match(s)}
=> ["hoho", "hihi", "haha"]
PCRE動詞スルー(*SKIP)(*F)
^hede$(*SKIP)(*F)|^.*$
これは、正確な文字列hede
を含む行を完全にスキップし、残りのすべての行に一致します。
部品の実行:
上記の正規表現を2つの部分に分けて考えてみましょう。
-
|
記号の前の部分。部分一致しないはず。^hede$(*SKIP)(*F)
-
^
記号の後の部分。パート一致する必要があります。^.*$
パート1
正規表現エンジンは、最初の部分から実行を開始します。
<*>説明:
-
$
開始時にアサートします。 -
(*F)
文字列と一致(*FAIL)
-
.*
行末にいることを表明します。
したがって、文字列.
を含む行が一致します。正規表現エンジンが次の*
(注:.+
を<=> と書くことができます)動詞を検出すると、スキップして一致を失敗させます。 <=>は、変更または論理OR演算子と呼ばれ、PCRE動詞の隣に追加されます。これは、正確な文字列<=>を含む行を除くすべての行の各文字間に存在するすべての境界に一致します。デモこちらをご覧ください。つまり、残りの文字列の文字との一致を試みます。これで、2番目の部分の正規表現が実行されます。
パート2
<*>説明:
- <=>開始時にアサートします。つまり、<=>行の行を除くすべての行の開始に一致します。 こちらのデモをご覧ください。
-
<=>複数行モードでは、<=>は改行文字または復帰文字を除くすべての文字に一致します。また、<=>は前の文字を0回以上繰り返します。したがって、<=>は行全体に一致します。デモをご覧くださいこちら。
。+の代わりに。*を追加した理由
<=>は空白行に一致しますが、<=>は空白に一致しないためです。 <=>を除くすべての行に一致させたい場合、入力にも空白行が含まれる可能性があります。したがって、<=>の代わりに<=>を使用する必要があります。 <=>は、前の文字を1回以上繰り返します。 <=>が空白行と一致するこちらを参照してください。
-
<=>ここで行末のアンカーは必要ありません。
質問された に対して他の誰も直接の回答を与えていないので、それを行います。
答えは、POSIX grep
では、この要求を文字通り満たすことは不可能だということです。
grep "Regex for doesn't contain hede" Input
理由は、POSIX \|
が基本的な正規表現。これは、そのタスクを達成するのに十分なほど強力ではありません(これらは、代替およびグループ化の欠如のため、正規言語を解析できません)。
ただし、GNU \(
はそれを可能にする拡張機能を実装しています。特に、\)
はGNUのBRE実装の代替演算子であり、egrep
およびtestinput.txt
はグループ化演算子です。正規表現エンジンが交互、負のブラケット式、グループ化、Kleeneスターをサポートし、文字列の先頭と末尾にアンカーできる場合、このアプローチに必要なのはそれだけです。
GNU hede
の場合、次のようになります。
grep "^\([^h]\|h\(h\|eh\|edh\)*\([^eh]\|e[^dh]\|ed[^eh]\)\)*\(\|h\(h\|eh\|edh\)*\(\|e\|ed\)\)$" Input
( Grailで見つかりましたおよびいくつかのさらなる最適化を手動で行います。)
拡張正規表現バックスラッシュを取り除くための<=>のようなa>:
egrep "^([^h]|h(h|eh|edh)*([^eh]|e[^dh]|ed[^eh]))*(|h(h|eh|edh)*(|e|ed))$" Input
テスト用のスクリプトを次に示します(現在のディレクトリにファイル<=>が生成されることに注意してください):
#!/bin/bash
REGEX="^\([^h]\|h\(h\|eh\|edh\)*\([^eh]\|e[^dh]\|ed[^eh]\)\)*\(\|h\(h\|eh\|edh\)*\(\|e\|ed\)\)$"
# First four lines as in OP's testcase.
cat > testinput.txt <<EOF
hoho
hihi
haha
hede
h
he
ah
head
ahead
ahed
aheda
ahede
hhede
hehede
hedhede
hehehehehehedehehe
hedecidedthat
EOF
diff -s -u <(grep -v hede testinput.txt) <(grep "$REGEX" testinput.txt)
私のシステムでは次のように印刷されます:
Files /dev/fd/63 and /dev/fd/62 are identical
期待どおり。
詳細に関心のある人のために、採用された手法は、単語に一致する正規表現を有限オートマトンに変換し、すべての受け入れ状態を非受け入れに、またはその逆に変換してオートマトンを反転し、結果を変換することですFAを正規表現に戻します。
最後に、誰もが指摘したように、正規表現エンジンがネガティブ先読みをサポートしている場合、タスクが大幅に簡素化されます。たとえば、GNU grepの場合:
grep -P '^((?!hede).)*$' Input
更新:最近、ケンドールホプキンスの優れた FormalTheory ライブラリが見つかりました、PHPで記述されており、Grailと同様の機能を提供します。それと、自分で作成した整理子を使用して、入力フレーズ(現在サポートされているのは英数字とスペース文字のみ)が与えられると、負の正規表現のオンラインジェネレーターを作成できました: http://www.formauri.es/personal/pgimeno/misc/non-match-regex/
<=>の場合、出力は次のとおりです。
^([^h]|h(h|e(h|dh))*([^eh]|e([^dh]|d[^eh])))*(h(h|e(h|dh))*(ed?)?)?$
上記と同等です。
コード内の2つの正規表現、1つ目は最初の一致を実行し、一致する場合は2つ目の正規表現を実行して異常値のケースをチェックし、たとえば^.*(hede).*
コード。
OK、これは実際に投稿された質問に対する回答ではなく、単一の正規表現よりもわずかに多くの処理を使用する可能性があることを認めます。しかし、外れ値の場合の迅速な緊急修正を求めてここに来た開発者にとっては、この解決策を見落としてはなりません。
TXR言語は、正規表現の否定をサポートしています。
$ txr -c '@(repeat)
@{nothede /~hede/}
@(do (put-line nothede))
@(end)' Input
より複雑な例:a
で始まりz
で終わるすべての行に一致するが、サブストリングhede
を含まない:
$ txr -c '@(repeat)
@{nothede /a.*z&~.*hede.*/}
@(do (put-line nothede))
@(end)' -
az <- echoed
az
abcz <- echoed
abcz
abhederz <- not echoed; contains hede
ahedez <- not echoed; contains hede
ace <- not echoed; does not end in z
ahedz <- echoed
ahedz
正規表現の否定はそれ自体では特に有用ではありませんが、交差がある場合は、ブール集合操作の完全なセットがあるため、物事が面白くなります:<!> quot;これに一致する集合を表現できますそれに一致するもの<!> quot;。
以下の関数は、目的の出力を取得するのに役立ちます
<?PHP
function removePrepositions($text){
$propositions=array('/\bfor\b/i','/\bthe\b/i');
if( count($propositions) > 0 ) {
foreach($propositions as $exceptionPhrase) {
$text = preg_replace($exceptionPhrase, '', trim($text));
}
$retval = trim($text);
}
return $retval;
}
?>
PCREのバックトラッキング制御動詞を使用して、単語を含まない行を一致させる方法
これまで使用したことのないメソッドを次に示します。
/.*hede(*COMMIT)^|/
仕組み
まず、<!> quot; hede <!> quot;を見つけようとします。行のどこかに。成功した場合、この時点で、(*COMMIT)
はエンジンに、障害が発生した場合にバックトラックするだけでなく、その場合はさらにマッチングを試行しないように指示します。次に、一致しない可能性のあるもの(この場合は^
)に一致させようとします。
行に<!> quot; hede <!> quotが含まれていない場合2番目の選択肢である空のサブパターンは、サブジェクト文字列と正常に一致します。
この方法はネガティブな先読みよりも効率的ではありませんが、誰かが気の利いたものを見つけ、他のより興味深いアプリケーションに使用できるようになった場合に備えて、ここに投げるだけだと考えました。
おそらく、 部分文字列を含まない行のセグメント(行全体ではなく)に一致する正規表現を記述しようとすると、Googleでこれを見つけることができます。しばらく理解していなかったので、共有します:
文字列を指定:
<span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>
サブストリング<!> quot; bad <!> quot;を含まない<span>
タグに一致させたい。
/<span(?:(?!bad).)*?>
は、<span class=\"good\">
および<span class=\"ugly\">
と一致します。
括弧のセット(レイヤー)が2つあることに注意してください:
- 最も内側のものはネガティブ先読み用です(キャプチャグループではありません)
- 最外部はRubyによってキャプチャグループとして解釈されますが、キャプチャグループにしたくないので、?:を追加しました。最初はキャプチャグループとして解釈されていません。
Rubyのデモ:
s = '<span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>'
s.scan(/<span(?:(?!bad).)*?>/)
# => ["<span class=\"good\">", "<span class=\"ugly\">"]
より簡単な解決策は、not演算子!
を使用することですif ステートメントは、<!> quot; contains <!> quot;と一致する必要があります。 <!> quot; excludes <!> quot;と一致しません。
var contains = /abc/;
var excludes =/hede/;
if(string.match(contains) && !(string.match(excludes))){ //proceed...
RegExの設計者は、not演算子の使用を予想していたと思います。
ConyEdit を使用すると、コマンドラインcc.gl !/hede/
を使用して、正規表現を含まない行を取得できます。または、コマンドラインcc.dl /hede/
を使用して、正規表現の一致を含む行を削除します。同じ結果になります。
^((?!hede).)*$ は洗練されたソリューションですが、文字を消費するため、他の条件と組み合わせることはできません。たとえば、「hede」の非現実と「ははは」の存在をチェックしたいとしました。このソリューションは、文字を消費しないために機能します。
^(?!.\bhede\b)(?=.\ばはは\b)