web-dev-qa-db-ja.com

単語を含まない行に一致させるための正規表現

Wordに一致させてから他のツール(grep -vなど)を使用して一致を元に戻すことが可能であることを私は知っています。ただし、特定の単語を含まない行を一致させることはできますか。 「ヘデ」、正規表現を使って?

入力:

hoho
hihi
haha
hede

コード:

grep "<Regex for 'doesn't contain hede'>" input

望ましい出力:

hoho
hihi
haha
3925
knaser

正規表現が逆マッチングをサポートしないという概念は完全に真実ではありません。負のルックアラウンドを使用して、この動作を模倣できます。

^((?!hede).)*$

上記の正規表現は、任意の文字列、または改行なしの行notに一致し、(sub)string 'hede'を含みます。前述のように、これは正規表現が「良い」(または行うべき)ものではありませんが、それでもは可能です

また、改行文字も一致させる必要がある場合は、 DOT-ALL修飾子 (次のパターンの末尾のs)を使用します。

/^((?!hede).)*$/s

またはインラインで使用します:

/(?s)^((?!hede).)*$/

/.../は正規表現の区切り文字です。つまり、パターンの一部ではありません)

DOT-ALL修飾子が使用できない場合、文字クラス[\s\S]で同じ動作を模倣できます。

/^((?!hede)[\s\S])*$/

説明

文字列は、n文字の単なるリストです。各文字の前後には、空の文字列があります。したがって、n文字のリストには、n+1空の文字列が含まれます。文字列"ABhedeCD"を考えてください:

    ┌──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┐
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

ここで、eは空の文字列です。正規表現(?!hede).は先読みして、表示されるサブストリング"hede"がないかどうかを確認し、その場合(他の何かが表示される場合)、.(ドット)が一致します改行を除く任意の文字。ルックアラウンドは、zero-width-assertionsとも呼ばれます。これは、文字を消費しないからです。彼らは何かを主張/検証するだけです。

したがって、私の例では、"hede"(ドット)によって文字が消費される前に、空の文字列がすべて.が先にないかどうかを最初に検証します。正規表現(?!hede).はそれを1回だけ行うため、グループにラップされ、0回以上繰り返されます:((?!hede).)*。最後に、入力全体が消費されるように、入力の開始と終了が固定されています:^((?!hede).)*$

ご覧のとおり、"ABhedeCD"では、正規表現e3が失敗するため、入力(?!hede)は失敗します(is"hede"この先!)。

5492
Bart Kiers

の解法は で始まらないことに注意してください “ hede”

^(?!hede).*$

を含まない 含まない “ hede” :に対する解決策よりも、一般にはるかに効率的です

^((?!hede).)*$

前者は、すべての位置ではなく、入力文字列の最初の位置でのみ "hede"をチェックします。

645
JoshuaDavid

If grepに使っているだけなので、grep -v hedeを使ってhedeを含まないすべての行を取得できます。

ETAああ、質問をもう一度読んで、grep -vはおそらくあなたが「ツールオプション」によって意味したものです。

178
Athena

答え:

^((?!hede).)*$

説明:

^文字列の先頭、 (グループ化して\ 1にキャプチャします(0回以上(可能な限りの量に一致))、
(?!がないかどうかを前もって見て、 

hedeあなたの文字列、 

)先読みの終わり、 .\n以外の任意の文字
)*末尾\ 1(注:このキャプチャでは数量詞を使用しているため、キャプチャしたパターンの最後の繰り返しのみ\ 1に格納されます)
$、オプションの\ nの前、および文字列の末尾

136
Jessica

与えられた答えは完全に素晴らしい、単なる学術的なポイントです。

理論的なコンピューター科学の意味での正規表現 ARE NOT ABLE /これは次のようにします。彼らにとってそれはこのような何かに見えなければなりませんでした:

^([^h].*$)|(h([^e].*$|$))|(he([^h].*$|$))|(heh([^e].*$|$))|(hehe.+$) 

これは完全一致のみを行います。サブマッチのためにそれをすることはさらに厄介です。

94
Hades32

全体の文字列 が一致する場合に正規表現テストを only failにしたい場合は、次のようにします。

^(?!hede$).*

例えば - "foo"以外のすべての値を許可する場合(つまり、 "foofoo"、 "barfoo"、および "foobar"は通過しますが、 "foo"は失敗します)、^(?!foo$).*を使用します。

もちろん、 exact equalityをチェックしているのであれば、この場合のより一般的な解決策は文字列が等しいかどうかをチェックすることです。 

myStr !== 'foo'

正規表現の機能が必要な場合は、否定 outside テストを追加することもできます(ここでは、大文字と小文字が区別されず、範囲が一致します)。

!/^[a-f]oo$/i.test(myStr)

ただし、この回答の冒頭にある正規表現による解決策は、正当な正規表現テストが必要な場合(おそらくAPIによるもの)には役に立ちます。

52
Roy Tinker

これが 良い説明 です。任意の正規表現を否定するのは簡単ではない理由です。私は他の答えに同意する必要があります、しかし:これが仮説的な質問以外の何かであれば、正規表現はここで正しい選択ではありません。

50
Josh Lee

FWIW、正規言語(別名有理言語)は補完の下で閉じられているので、別の表現を否定する正規表現(別名有理式)を見つけることは常に可能です。しかし、これを実装するツールはそれほど多くありません。

Vcsn はこの演算子をサポートします(これは{c}、postfixを表します)。

最初に式のタイプを定義します。ラベルはaからzまでを選択するための文字(lal_char)です(補完を扱うときのアルファベットの定義はもちろん非常に重要です)。単なるブール値:Wordは受け入れられますtruefalseは拒否されます。

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

The corresponding automaton

最後に、このオートマトンを単純な式に戻します。

In [8]: print(a.expression())
        \e+h(\e+e(\e+d))+([^h]+h([^e]+e([^d]+d([^e]+e[^]))))[^]*

+は通常|を表し、\eは空のWordを表し、[^]は通常.(任意の文字)と表記されます。そのため、()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).*を少し書き換えます。

あなたはこの例を見ることができます ここ 、そしてVcsnをオンラインで試す そこ

49
akim

ベンチマーク

提示されたオプションのいくつかを評価し、それらのパフォーマンスを比較し、いくつかの新しい機能を使用することにしました。 .NET Regex Engineでのベンチマーク: 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回の実行の中央値としての毎秒の反復数です - 大きい数=良い

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))*$ resultsに展開することができます。わずかなパフォーマンスの向上。

しかし、全体的に最も読みやすくパフォーマンス上最速の解決策は、条件付きステートメントを使用した場合は05、所有量指定子を使用した場合は04です。私は、Perlのソリューションはもっと速く、もっと読みやすいものにすべきだと思います。

41
Falco

否定的な先読みでは、正規表現は特定のパターンを含まないものと一致する可能性があります。これはBart Kiersによって答えられ、説明されています。いい説明だ!

ただし、Bart Kiersの回答では、先読み部分は1文字から4文字を先にテストしながら、任意の1文字を照合します。これを避けて先読み部分にテキスト全体をチェックアウトさせ、 'hede'がないことを確認してから、通常部分(。*)がテキスト全体を一度に食べることができます。

これが改良された正規表現です。

/^(?!.*?hede).*$/

負の先読み部分の(*?)遅延量指定子はオプションであることに注意してください。データによっては、代わりに(*)欲張り量指定子を使用できます。速くなります。そうでなければ、欲張り数量詞は速くなります。ただし、「hede」が表示されていない場合は、どちらも遅くなります。

これは デモコードです

先読みの詳細については、次の記事を参照してください。 マスタリング先読みと先読み

また、 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()
);
40
amobiz

正規表現ではありませんが、ノイズを除去するためにパイプ付きのシリアルgrepを使用するのが論理的で便利なことがわかりました。

例えば。コメントなしでApacheの設定ファイルを検索する

grep -v '\#' /opt/lampp/etc/httpd.conf      # this gives all the non-comment lines

そして

grep -v '\#' /opt/lampp/etc/httpd.conf |  grep -i dir

シリアルgrepのロジックは(コメントではありません)および(dirに一致します)です。

32
kiwalk

これにより、各ポジションで先読みをテストすることを避けます

/^(?:[^h]+|h++(?!ede))*+$/

(.netの場合)と同等です。

^(?>(?:[^h]+|h+(?!ede))*)$

古い答え:

/^(?>[^h]+|h+(?!ede))*$/
28

これが私のやり方です。

^[^h]*(h(?!ede)[^h]*)*$

他の答えよりも正確かつ効率的です。これはFriedlの "ループの展開" の効率化技術を実装しており、バックトラックの必要性がはるかに少なくなります。

19
ridgerunner

前述の(?:(?!hede).)*は固定できるので素晴らしいです。

^(?:(?!hede).)*$               # A line without hede

foo(?:(?!hede).)*bar           # foo followed by bar, without hede between them

しかし、この場合は以下で十分です。

^(?!.*hede)                    # A line without hede

この単純化により、 "AND"句を追加する準備が整いました。

^(?!.*hede)(?=.*foo)(?=.*bar)   # A line with foo and bar, but without hede
^(?!.*hede)(?=.*foo).*bar       # Same
18
ikegami

文字クラスを無効にするのと同様に、Wordを無効にするために文字を照合する場合は、次のように入力します。

たとえば、文字列:

<?
$str="aaa        bbb4      aaa     bbb7";
?>

使ってはいけません:

<?
preg_match('/aaa[^bbb]+?bbb7/s', $str, $matches);
?>

つかいます:

<?
preg_match('/aaa(?:(?!bbb).)+?bbb7/s', $str, $matches);
?>

"(?!bbb)."は先読みでも先読みでもないことに注意してください。例えば、次のようになります。

"(?=abc)abcde", "(?!abc)abcde"
17
diyism

OPが指定しなかった、または Tag 正規表現が使用されるコンテキスト(プログラミング言語、エディタ、ツール)を示す投稿。

私にとっては、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を含みます。すべての行から一意の "Tag"を削除します(置換文字列は空です)。

    Search string:<@#-unique-#@>
    Replace string:<nothing>  
    Replace-all  

文字列hedeを含むすべての行が削除された元のテキストができました。


探しているなら 他に何かする その行だけに しない 文字列hedeが含まれているとします。

1.ファイル全体を検索/置換して、テキストを含む各行の先頭に一意の「タグ」を追加します。

    Search string:^(.)  
    Replace string:<@#-unique-#@>\1  
    Replace-all  

2.文字列hedeを含むすべての行について、一意の "Tag"を削除します。

    Search string:<@#-unique-#@>(.*hede)
    Replace string:\1  
    Replace-all  

3.この時点で、一意の "Tag"で始まるすべての行 しない 文字列hedeを含みます。私は今できる それ以外のもの それらの行だけに。

4.終了したら、すべての行から一意の "Tag"を削除します(置換文字列は空です)。

    Search string:<@#-unique-#@>
    Replace string:<nothing>  
    Replace-all  
13
Kevin Fegan

Ruby-2.4.1の導入以来、私たちは新しい 不在演算子 をRubyの正規表現で使うことができます。

公式から doc

(?~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"]
9
aelor

他の誰もそれは尋ねられた _質問に直接答えを出していないので、私はそれをするつもりです。

その答えは、POSIXのgrepでは、この要求を文字通り満たすことは不可能だということです。

grep "Regex for doesn't contain hede" Input

その理由は、POSIXのgrep基本正規表現 でのみ動作することを要求されるためです。これは、そのタスクを実行するためには十分に強力ではありません。

しかし、GNU grepはそれを可能にする拡張を実装しています。特に、\|はGNUによるBREの実装における代替演算子で、\(\)はグループ化演算子です。あなたの正規表現エンジンが交替、否定括弧表現、グルーピング、Kleene starをサポートしていて、文字列の始めと終わりに固定できるのであれば、このアプローチに必要なのはそれだけです。

GNU grepの場合は、次のようになります。

grep "^\([^h]\|h\(h\|eh\|edh\)*\([^eh]\|e[^dh]\|ed[^eh]\)\)*\(\|h\(h\|eh\|edh\)*\(\|e\|ed\)\)$" Input

Grail と、さらに手作業で行った最適化で見つかります)。

egrepのように、 Extended Regular Expressions を実装したツールを使ってバックスラッシュを取り除くこともできます。

egrep "^([^h]|h(h|eh|edh)*([^eh]|e[^dh]|ed[^eh]))*(|h(h|eh|edh)*(|e|ed))$" Input

これをテストするスクリプトがあります(現在のディレクトリにtestinput.txtというファイルが生成されます)。

#!/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

予想通り。

詳細に興味がある人のために、採用されたテクニックは、Wordにマッチする正規表現を有限オートマトンに変換し、次にすべての受け入れ状態を非受け入れに、そしてその逆に変換することによってオートマトンを逆にし、そして結果のFAを正規表現.

最後に、皆さんがおっしゃったように、あなたの正規表現エンジンがネガティブルックアヘッドをサポートしていれば、タスクが非常に簡単になります。たとえば、GNU grepの場合、

grep -P '^((?!hede).)*$' Input

更新: 最近、PHPで書かれたKendall Hopkinsのすばらしい FormalTheory ライブラリが見つかりました。これはGrailに似た機能を提供します。それを使って、そして私自身が書いた単純化して、私は入力句を与えられた負の正規表現のオンラインジェネレータを書くことができました(現在サポートされているのは英数字とスペース文字だけです): http://www.formauri.es/ personal/pgimeno/misc /不一致正規表現/

hedeの場合、次のように出力されます。

^([^h]|h(h|e(h|dh))*([^eh]|e([^dh]|d[^eh])))*(h(h|e(h|dh))*(ed?)?)?$

上記と同等です。

8
Pedro Gimeno

PCRE動詞を介して(*SKIP)(*F)

^hede$(*SKIP)(*F)|^.*$

これは、正確な文字列hedeを含む行を完全にスキップし、残りのすべての行に一致します。

デモ

パーツの実行:

上記の正規表現を2つに分割して考えてみましょう。

  1. |シンボルの前の部分部分 は一致してはいけません 。 

    ^hede$(*SKIP)(*F)
    
  2. |シンボルの後の部分部分 は一致しなければならない 。 

    ^.*$
    

第1部  

正規表現エンジンは最初の部分から実行を開始します。

^hede$(*SKIP)(*F)

説明:

  • ^私たちが始めていることを表明します。
  • hede文字列hedeに一致します
  • $行末にいることを表明します。

そのため、文字列hedeを含む行が一致します。正規表現エンジンが次の(*SKIP)(*F)注:(*F)(*FAIL))動詞を見つけると、スキップして一致しないようにします。 inturnがすべての行の正確な文字列hedeを除くすべての行の各文字の間に存在するすべての境界に一致する、PCRE動詞の隣に追加された、変更または論理OR演算子と呼ばれる|演算子。デモを見る ここ 。つまり、残りの文字列の文字と一致させようとします。これで2番目の部分の正規表現が実行されます。

パート2

^.*$

説明:

  • ^私たちが始めていることを表明します。つまり、hede行の行を除くすべての行の先頭に一致します。デモを見る ここ
  • .*マルチラインモードでは、.は改行文字またはキャリッジリターン文字を除くすべての文字と一致します。そして*は前の文字を0回以上繰り返します。そのため.*は行全体に一致します。デモを見る ここ

    なぜあなたは。+の代わりに。*を追加したのですか?

    .*は空白行と一致しますが、.+は空白と一致しません。 hedeを除くすべての行を一致させたいのですが、入力にも空白行が含まれる可能性があります。そのため、.*の代わりに.+を使用する必要があります。 .+は前の文字を1回以上繰り返します。 .*が空白行 here に一致するを参照してください。

  • $行末アンカーはここでは必要ありません。

8
Avinash Raj

1つは最初の一致を行い、2つ目の正規表現を実行して^.*(hede).*のようにブロックしたい異常値のケースをチェックすると、コードに適切なロジックが含まれます。

はい、これは投稿された質問に対する回答ではないことを認めます。また、単一の正規表現よりも多少処理が多くなる可能性があります。しかし、ここに来て開発者が外れ値のケースに対する迅速な緊急修正を探しているなら、この解決策を見逃してはいけません。

6
andrew pate

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

正規表現の否定はそれ自体では特に有用ではありませんが、交差があるとき、物事は面白くなります。ブール集合演算の完全な集合を持っているからです。

5
Kaz

以下の機能はあなたがあなたの希望する出力を得るのを助けるでしょう

<?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;
    }


?>
3
Daniel Nyamasyo

私の意見では、トップ答えのより読みやすい変形: 

^(?!.*hede)

基本的に、「行頭にマッチ」がない場合に限り、行の先頭で一致します。つまり、要件はほぼ直接正規表現に変換されます。

もちろん、複数の障害要件がある可能性もあります。

^(?!.*(hede|hodo|hada))

詳細: ^アンカーは、正規表現エンジンが文字列内のあらゆる場所でマッチを再試行しないことを保証します。

先頭の^アンカーは、行の先頭を表すためのものです。 grepツールは、各行を1行ずつ照合します。複数行の文字列を扱う場合は、 "m"フラグを使用できます。

/^(?!.*hede)/m # JavaScript syntax

または

(?m)^(?!.*hede) # Inline flag
3
staafl

別のオプションは、正の先読みを追加し、heheが入力行のどこかにあるかどうかを確認することです。次に、次のような式でそれを無効にします。

^(?!(?=.*\bhede\b)).*$

単語の境界で。


式は regex101.com の右上のパネルで説明されています。探索/単純化/変更する場合は このリンク で、どのように表示されるかを確認できます。必要に応じて、いくつかのサンプル入力と一致します。


正規表現回路

jex.im は正規表現を視覚化します:

enter image description here

1
Emma

ConyEdit を使用すると、正規表現の一致を含まない行を取得するにはコマンドラインcc.gl !/hede/を使用でき、正規表現の一致を含む行を削除するにはコマンドラインcc.dl /hede/を使用できます。それらは同じ結果になります。

0
Donald

部分文字列を含むnotを含む(行全体ではなく)行のセグメントに一致することができる正規表現を作成しようとしているときに、Googleでこれを見つけることができるでしょう。少し時間をかけて把握しているので、共有します。

与えられた文字列: <span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>

部分文字列 "bad"を含まない<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\">"]
0
BrunoFacca

PCREのバックトラッキング制御動詞を使用して、Wordを含まない行と一致させる方法

これまで私が使ったことのない方法です。

/.*hede(*COMMIT)^|/

使い方

まず、行のどこかで "hede"を見つけようとします。成功した場合、この時点で(*COMMIT)は、失敗した場合にバックトラックするだけでなく、その場合それ以上マッチングを試みないようにエンジンに指示します。次に、一致しない可能性があるもの(この場合は^)と一致させます。

行に "hede"が含まれていない場合は、2番目の選択肢、空のサブパターンがサブジェクト文字列と正常に一致します。

この方法はネガティブルックアヘッドよりも効率的ではありませんが、気の利いたものが見つかり、他のもっと面白いアプリケーションに使用することができれば、ここでそれを使用することにします。

0
jaytea

^((?! hede)。)* $は文字を消費するので他の基準と組み合わせることはできないという点を除けば、エレガントな解決策です。たとえば、 "hede"が存在しないことと "haha"が存在することを確認したいとします。このソリューションは文字を消費しないのでうまくいきます。

^(?!.\bhede\b)(?=。 \ bhaha\b)

0

もっと簡単な解決策はnot演算子 を使うことです。

あなたの if ステートメントは "contains"にマッチし、 "exclude"にマッチしない必要があります。

var contains = /abc/;
var excludes =/hede/;

if(string.match(contains) && !(string.match(excludes))){  //proceed...

私は、RegExの設計者は演算子ではなくて使用することを期待していたと思います。

0
JohnP2