単語を含まない行に一致する正規表現


4294

単語を一致させてから、他のツール(などgrep -v)を使用して一致を逆にすることは可能です。しかし、たとえばhede正規表現を使用して、特定の単語を含まない行を一致させることは可能ですか?

入力:

hoho
hihi
haha
hede

コード:

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

望ましい出力:

hoho
hihi
haha

85
おそらく数年遅れますが、何が問題になっています([^h]*(h([^e]|$)|he([^d]|$)|hed([^e]|$)))*か?アイデアは簡単です。不要な文字列の先頭が表示されるまで照合を続け、次に、文字列が完成していないN-1の場合にのみ照合します(Nは文字列の長さです)。これらのN-1ケースは、「hの後に非eが続く」、「彼の後に非dが続く」、「hedの後に非eが続く」です。これらのN-1ケースを何とか通過できた場合、成功しませんでした、不要な文字列に一致ため、[^h]*もう一度
検索を

323
@stevendesu:「a-very-very-long-word」またはさらに良い半文にこれを試してください。タイピングを楽しんでください。ところで、それはほとんど読めません。パフォーマンスへの影響はわかりません。
Peter Schuetze、2012年

13
@PeterSchuetze:確かに、非常に長い単語には不向きですが、実行可能で正しいソリューションです。私はパフォーマンスのテストを実行していませんが、h(または単語、文などの最初の文字)が表示されるまでほとんどの後者のルールが無視されるため、速度が遅すぎるとは思えません。また、反復連結を使用して、長い文字列の正規表現文字列を簡単に生成できます。それが機能し、すぐに生成できる場合、読みやすさは重要ですか?それがコメントの目的です。
stevendesu

57
@stevendesu:私はもっと遅いですが、その答えはほぼ完全に間違っています。1つには、タスクに「特定の単語を含まない[一致する]行を一致させる」というタスクがある場合、件名に「h」を含める必要はありません。内部グループをオプションにするつもりであり、パターンが固定されているとしましょう。 ^([^h]*(h([^e]|$)|he([^d]|$)|hed([^e]|$))?)*$ これは、「hede」のインスタンスの前に「hhede」のように「hede」の部分インスタンスが先行している場合に失敗します。
jaytea 2012

8
この質問は、スタックオーバーフローの正規表現に関するFAQの「Advanced Regex-Fu」に追加されました。
aliteralmind 2014

回答:


5895

正規表現が逆マッチングをサポートしていないという考えは完全には当てはまりません。ネガティブルックアラウンドを使用して、この動作を模倣できます。

^((?!hede).)*$

上記の正規表現は、任意の文字列、または改行なしの行に一致します。 (サブ)文字列 '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"される部分文字列がないかどうかを確認し、それが当てはまる場合(他に何かが表示される場合)、.(ドット)は改行を除くすべての文字と一致します。ルックアラウンドは文字を消費しないため、ゼロ幅アサーションとも呼ばれます。彼らは何かを主張/検証するだけです。

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

あなたが見ることができるように、入力が"ABhedeCD"あるために失敗するe3正規表現は、(?!hede)失敗した(そこ "hede"先にアップ!)。


26
これは正規表現が得意ではないことだとは言えません。このソリューションの利便性は明白であり、プログラムによる検索と比較した場合のパフォーマンスへの影響は、多くの場合重要ではありません。
アルキマレデス2016

29
厳密に言えば、否定的な先読みは、正規表現を通常ではないものにします。
Peter K

55
@PeterK、確かに、これはSOであり、MathOverflowやCS-Stackexchangeではありません。ここで質問をする人々は一般的に実用的な答えを探しています。grep正規表現サポートを備えたほとんどのライブラリまたはツール(OPで言及されているのような)はすべて、理論的な意味で非正規化する機能を備えています。
Bart Kiers、2016年

19
@Bart Kiers、あなたに答えるのに害はありません、この用語の乱用だけが私を少し苛立たせます。ここで本当に混乱する部分は、厳密な意味での正規表現はOPが望むことを非常に実行できるということですが、それらを記述する共通言語では許可されないため、先読みのような(数学的には醜い)回避策につながります。以下のこの回答と、そこに(理論的には)適切な方法についての私のコメントを参照しください。言うまでもなく、これは大きな入力でより速く動作します。
Peter K

17
vimでこれを行う方法を疑問に思った場合:^\(\(hede\)\@!.\)*$
はげ頭'24年

739

へのソリューション「hede」で始まっいないことに注意してください:

^(?!hede).*$

一般に「hede」を含まないソリューションよりもはるかに効率的です。

^((?!hede).)*$

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


5
おかげで、文字列に数字のシーケンスが含まれていないことを検証するためにそれを使用しました^((?!\ d {5、}))*
Samih A

2
こんにちは!作れないのですが、「へで」正規表現で終わっいません。お手伝いできますか?
Aleks Ya

1
@AleksYa:「contain」バージョンを使用し、検索文字列に終了アンカーを含める:文字列を「hede」から「hede $」に「not match」に変更
Nyerguds

2
@AleksYa:終了しないバージョンは、次のように否定的な後読みを使用して実行できます(.*)(?<!hede)$。@Nyergudsのバージョンも機能しますが、回答が述べているパフォーマンスのポイントを完全に逃しています。
thisismydesign

5
なぜそれほど多くの答えが言っているの^((?!hede).)*$ですか?使用する方が効率的ではありません^(?!.*hede).*$か?同じことを行いますが、手順は少なくなります
JackPRead

208

単にgrepに使用している場合grep -v hedeは、hedeを含まないすべての行を取得するために使用できます。

ETAああ、質問をもう一度読んでgrep -vください。おそらく、「ツールオプション」が意味するものです。


22
ヒント:不要なものを段階的に除外するには:grep -v "hede" | grep -v "hihi" | ...等。
Olivier Lalonde 2014

51
または、1つのプロセスのみを使用grep -v -e hede -e hihi -e ...
Olaf Dietsche '26

15
または単にgrep -v "hede\|hihi":)
Putnik

2
除外したいパターンがたくさんある場合は、それらをファイルに入れて使用しますgrep -vf pattern_file file
codeforester '11年

4
または単にegrepまたは grep -Ev "hede|hihi|etc"厄介な脱出を避けるために。
アミットナイドゥ2018年

160

回答:

^((?!hede).)*$

説明:

^文字列の先頭、 (グループ化、およびキャプチャを\ 1に(0回以上(可能な限り多くの量に一致))、
(?!ないかどうかを確認します。

hede あなたのひも、

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


14
複数の単語 ' ^((?!DSAU_PW8882WEB2|DSAU_PW8884WEB2|DSAU_PW8884WEB).)*$' を使用した崇高なテキスト2で私のために働いた素晴らしいもの
Damodar Bashyal

3
@DamodarBashyal私はここでかなり遅れていることを知っていますが、2番目の用語を完全に削除して、まったく同じ結果を得ることができます
forresthopkinsa

99

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

理論的なコンピュータサイエンスの意味での正規表現は、このようにすることはできません。彼らにとって、それはこのようなものでなければなりませんでした:

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

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


1
これは、基本的なPOSIX.2正規表現のみを使用するため、PCREが使用できない場合は簡潔であることに注意してください。
Steve-o

5
同意する。ほとんどとは言わないまでも多くの正規表現は正規言語ではなく、有限オートマトンで認識できませんでした。
ThomasMcLeod 14年

@ ThomasMcLeod、Hades32: ' not 'と ' and 'だけでなく、 '' などの式の' または ' を言うことができるのは、あらゆる通常の言語の領域内(hede|Hihi)ですか?(これはおそらくCSの質問です。)
James Haigh

7
@JohnAllen:ME !!! …まあ、実際の正規表現ではなく、計算の複雑さに密接に関連する学問的な参照。PCREは基本的に、POSIX正規表現と同じ効率を保証できません。
James Haigh

4
申し訳ありません-この答えはうまくいきません、それはheheheにマッチし、heheに部分的にマッチします(後半)
ファルコ

60

文字列全体が一致した場合にのみ正規表現テストが失敗するようにしたい場合は、以下が機能します。

^(?!hede$).*

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

もちろん、正確な等価性をチェックする場合、この場合のより一般的な解決策は、文字列の等価性をチェックすることです。

myStr !== 'foo'

正規表現機能(ここでは、大文字と小文字の区別と範囲の一致)が必要な場合は、否定をテストの外に置くこともできます。

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

この回答の上部にある正規表現ソリューションは、(おそらくAPIによって)肯定的な正規表現テストが必要な状況で役立つ場合があります。


末尾の空白についてはどうですか?たとえば、テストを文字列で失敗させたい場合は" hede "
eagor

@eagor \sディレクティブは単一の空白文字に一致します
Roy Tinker

おかげで、しかし私はこの作業をするために正規表現を更新することができませんでした。
熱心な

2
@eagor:^(?!\s*hede\s*$).*
Roy Tinker

52

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

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

最初に、式のタイプを定義します。ラベルは、たとえばlal_char、選択aするzための文字()です(もちろん、補完を処理するときにアルファベットを定義することは非常に重要です)。各単語に対して計算される「値」は単なるブール値です: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.)))).*ます。

この例をここで見ることができ、Vcsnをオンライン試すことができます。


6
真の、しかし醜い、そして小さな文字セットに対してのみ実行可能です。Unicode文字列でこれを実行したくない:-)
reinierpost

それを可能にするツールは他にもありますが、最も印象的なのはRagelです。そこでは、開始位置合わせの一致の場合は(any *-( 'hehe' any *))として、非位置合わせの場合は(any *-( 'hehe' any *))として記述されます。
Peter K

1
@reinierpost:なぜそれは醜いのですか?ユニコードの問題は何ですか?私は両方に同意することはできません。(私はvcsnの経験はありませんが、DFAの経験はあります)。
Peter K

3
@PedroGimenoあなたがアンカーしたとき、あなたはこの正規表現を最初に括弧に入れることを確実にしましたか?そうし|ないと、アンカー間の優先順位が高くなり、うまく機能しません。 '^(()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).*)$'
akimが

1
このメソッドは、OPが要求した「hede」という単語を含まない行ではなく、「hede」という単語ではない行を照合するためのものであることに注意する価値があると思います。後者については私の答えを参照してください。
Pedro Gimeno

51

ここだ良い説明それは任意の正規表現を否定することは容易ではありません理由のは。ただし、他の回答にも同意する必要があります。これが仮説的な質問以外の場合、正規表現はここでは適切な選択ではありません。


10
一部のツール、特にmysqldumpslowは、この方法でデータをフィルタリングすることしかできないため、このような場合、これを行う正規表現を見つけることは、ツールを書き直す以外の最良のソリューションです(このためのさまざまなパッチはMySQL AB / Sunに含まれていません) / Oracle
FGM 2012

1
私の状況とまったく同じです。Velocityテンプレートエンジンは、正規表現を使用していつ変換(escape html)を適用するかを決定します。ある状況では常にそれが機能しないようにします。
Henno Vermeulen 2013

1
代替案はありますか?正規表現以外に、正確な文字列照合を行うことができるものに出会ったことはありません。OPがプログラミング言語を使用している場合、他に利用可能なツールがあるかもしれませんが、彼/彼女がコードを書かないで使用している場合、おそらく他の選択肢はありません。
kingfrito_5005 2016年

2
正規表現が最良の選択肢である多くの非仮想シナリオの1つ:ログ出力を表示するIDE(Android Studio)にいます。提供されるフィルターツールは、プレーンストリングと正規表現のみです。プレーンな文字列でこれを実行しようとすると、完全に失敗します。
LarsH

48

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

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

改善された正規表現は次のとおりです。

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

否定先読み部分の(*?)遅延量指定子はオプションであることに注意してください。代わりに、データに応じて(*)貪欲量指定子を使用できます。より速くなる; それ以外の場合、貪欲な量指定子はより高速です。ただし、「hede」が存在しない場合は、どちらも低速になります。

こちらがデモコードです。

先読みの詳細については、優れた記事「Mastering Lookahead and Lookbehind」をご覧ください。

また、複雑な正規表現の作成に役立つJavaScript正規表現ジェネレーターであるRegexGen.jsも確認してください。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()
);

3
その与えられた文字列がSTR1とstr2が含まれていない場合は、単に確認するには:^(?!.*(str1|str2)).*$
S.Serpooshan

1
はい、または^(?!.*?(?:str1|str2)).*$データに応じて、遅延数量詞:を使用できます。?:キャプチャする必要がないため、追加されました。
amobiz

これは、10xmsの係数で断然最高の答えです。jsfiddleコードと結果を回答に追加すると、人々はそれに気付くでしょう。hedeがない場合、なぜ遅延バージョンが貪欲バージョンより速いのかと思います。彼らは同じ時間をかけるべきではありませんか?
user5389726598465

はい、どちらもテキスト全体をテストするため、同じ時間がかかります。
amobiz 2017

41

ベンチマーク

提示されたオプションのいくつかを評価し、それらのパフォーマンスを比較することに加えて、いくつかの新しい機能を使用することにしました。.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ソリューションはさらに高速で読みやすいはずだと思います。


5
あなた^(?!.*hede)も時間をかけるべきです。///また、通常、ほとんどの行が一致するかほとんどの行が一致しない場合があるため、一致するコーパスと一致しないコーパスの式を別々にランク付けする方が良いでしょう。
池上

32

正規表現ではありませんが、シリアルグレップをパイプで使用してノイズを除去することが論理的で便利であることがわかりました。

例えば。すべてのコメントなしで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に一致)です。


2
私は彼がの正規表現バージョンを求めていると思うgrep -v
Angel.King.47

9
これは危険です。次のような行も欠落していますgood_stuff #comment_stuff
Xavi Montero

29

これにより、各ポジションで先読みをテストする必要がなくなります。

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

(.netの場合)と同等:

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

古い答え:

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

7
いい視点ね; これまで誰もこのアプローチに言及しなかったのには驚きです。ただし、その特定の正規表現は、一致しないテキストに適用されると、壊滅的なバックトラックが発生しやすくなります。これが私のやり方です:/^[^h]*(?:h+(?!ede)[^h]*)*$/
アラン・ムーア

...または、すべての数量詞を所有格にすることができます。;)
アランムーア

@Alan Moore-私も驚いています。以下の回答でこの同じパターンを投稿した後にのみ、ここであなたのコメント(および山の中での最高の正規表現)を見ました。
ridgerunner 2013

@ridgerunner、最高のトーである必要はありません。上位の回答のパフォーマンスが向上するベンチマークを見てきました。(私はそのことについて驚いた。)
Qtax

23

前述の (?:(?!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

20

ここに私がそれをする方法があります:

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

他の回答よりも正確で効率的です。Friedlの「unrolling-the-loop」効率化手法を実装しており、必要なバックトラックがはるかに少なくなります。


17

文字を一致させて、文字クラスを否定するような単語を否定したい場合:

たとえば、文字列:

<?
$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"

3
perlの正規表現には「lookcurrent」はありません。これは本当に否定的な先読みです(接頭辞(?!)。(?=正の先読みの接頭辞は、対応する先読みの接頭辞がそれぞれに(?<!あり(?<=ます。先読みとは、次の文字(つまり「前」)を消費せずに読み取ることを意味します。後読みとは、すでに消費されている文字を確認することを意味します。
Didier L

14

私の意見では、トップアンサーのより読みやすいバリエーション:

^(?!.*hede)

基本的に、「行頭に一致するのは、「hede」が含まれていない場合に限られます」-したがって、要件はほぼ直接正規表現に変換されます。

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

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

詳細: ^アンカーは、正規表現エンジンが文字列のすべての場所で一致を再試行しないことを保証します。

先頭の^アンカーは、行の先頭を表すためのものです。grepツールは、一度に各行を1つずつ照合します。複数行の文字列で作業しているコンテキストでは、「m」フラグを使用できます。

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

または

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

複数の否定がある優れた例。
Peter Parada

トップの答えから一つの違い、これは何も一致していないということであり、それは「hede」がなければ、行全体にマッチする
Z. Khullah

13

OPはTag、Regexがその中で使用されるコンテキスト(プログラミング言語、エディター、ツール)を示すための投稿を指定しませんでした。

私にとって、を使用してファイルを編集しているときに、これを行う必要がある場合がありますTextpad

Textpad は一部のRegexをサポートしていますが、先読みや後読みはサポートしていないため、いくつかの手順を実行します。

文字列を含まないすべての行を保持し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削除された元のテキストが得られました。


私がするのを楽しみにしていた場合は、何か他のものを実行してくださいということだけラインにDOはしない文字列が含まれているhede、私はこのようにそれを行うだろう。

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

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

2.文字列を含むすべての行でhede、一意の「タグ」を削除します。

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

3.この時点で、一意の「タグ」で始まるすべての行には、文字列を含めないくださいhede。これで、Something Elseをこれらの行にのみ実行できます。

4.完了したら、すべての行から一意の「タグ」を削除します(置換文字列は空です)。

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

12

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

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

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

その理由は、POSIX grep基本的な正規表現でのみ動作する必要があるためです。で。これらは、そのタスクを実行するのに十分強力ではありません(代替と括弧がないため、正規言語を解析できません)。

ただし、GNU grepはそれを可能にする拡張機能を実装しています。特に、\|BREとのGNUの実装で交代演算子であり、そして\(そして\)括弧です。正規表現エンジンが代替、負のブラケット式、括弧、およびKleeneスターをサポートし、文字列の最初と最後にアンカーできる場合、この方法で必要なのはそれだけです。ただし、ネガティブセット[^ ... ]はこれらに加えて非常に便利です。それ以外の場合(a|b|c| ... )は、セットに含まれていないすべての文字をリストするフォームの式に置き換える必要があります。これは、非常に面倒で長すぎるため、さらに文字セット全体がUnicodeです。

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

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

Grailと、手動で行われたいくつかのさらなる最適化で見つかりました)。

また、実装は、そのツールを使用することができます正規表現を拡張ように、egrepバックスラッシュを取り除くために、:

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

予想通り。

詳細に関心のある人は、単語に一致する正規表現を有限オートマトンに変換し、すべての受け入れ状態を非受け入れ状態に、またはその逆に変更してオートマトンを反転し、結果のFAを正規表現。

最後に、誰もが指摘しているように、正規表現エンジンが否定先読みをサポートしている場合は、タスクが大幅に簡略化されます。たとえば、GNU grepの場合:

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

更新:私は最近、PHPで記述されたKendall Hopkinsの優れたFormalTheoryライブラリを見つけました。これは、Grailと同様の機能を提供します。それを使用して、自分で作成した単純化プログラムを使用して、入力句(現在サポートされている英数字とスペース文字のみ)を指定して、負の正規表現のオンラインジェネレーターを作成できました。http//www.formauri.es/personal/ pgimeno / misc / non-match-regex /

それのためhedeに出力します:

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

上記と同等です。


11

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"]

9

PCRE動詞を通じて (*SKIP)(*F)

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

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

デモ

パーツの実行:

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

  1. |記号の前の部分。パーツを一致させないでください

    ^hede$(*SKIP)(*F)
  2. |シンボルの後の部分。パーツを一致させる必要があります

    ^.*$

パート1

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

^hede$(*SKIP)(*F)

説明:

  • ^ 私たちは最初にいると主張します。
  • hede 文字列に一致します hede
  • $ 行末にいることを表明します。

したがって、文字列を含む行hedeが一致します。正規表現エンジンが次の(*SKIP)(*F)注:(*F)として書くこともできます(*FAIL))動詞を検出すると、スキップして一致を失敗させます。|PCRE動詞の横に追加と呼ばれる変更または論理OR演算子が追加されますhede。これは、行が正確な文字列を含む以外のすべての行のすべての文字の間に存在するすべての境界に一致するすべての境界に一致します。こちらのデモをご覧ください。つまり、残りの文字列の文字を照合しようとします。これで、2番目の部分の正規表現が実行されます。

パート2

^.*$

説明:

  • ^ 私たちは最初にいると主張します。つまり、行の先頭以外のすべての行の先頭に一致しますhede。こちらのデモをご覧ください
  • .*マルチラインモードで.は、改行または復帰文字を除くすべての文字に一致します。そして*、前の文字を0回以上繰り返します。したがって.*、行全体と一致します。こちらのデモをご覧ください

    。+ではなく。*を追加した理由

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

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


7

コード内の2つの正規表現でより保守しやすくなる可能性があります。1つは最初の一致を実行し、一致した場合は2番目の正規表現を実行して異常値のケースをチェック^.*(hede).*します。たとえば、ブロックしたい場合は、コードに適切なロジックがあります。

OK、これは投稿された質問への回答ではなく、単一の正規表現よりもわずかに多くの処理を使用する可能性があることを認めます。しかし、異常値のケースに対する迅速な緊急修正を探してここに来た開発者にとっては、このソリューションを見落としてはなりません。


6

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

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

単語の境界で。


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


RegEx回路

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

ここに画像の説明を入力してください


5

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

正規表現の否定は、それ自体では特に有用ではありませんが、ブール集合演算の完全なセットがあるため、交差も存在する場合、興味深いことが起こります。「これに一致するものを除いて、これに一致するセット」を表現できます。


これは、ElasticSearch Luceneベースの正規表現のソリューションでもあることに注意してください。
WiktorStribiżew18年

4

以下の関数は、目的の出力を得るのに役立ちます

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


?>

2

^((?! hede)。)* $はエレガントなソリューションですが、文字を消費するため、他の基準と組み合わせることはできません。たとえば、「へで」の非存在と「はは」の存在を確認したいとします。このソリューションは、文字を消費しないため機能します。

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


1

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

これは、私が以前に使用したことのない方法です。

/.*hede(*COMMIT)^|/

使い方

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

行に「hede」が含まれていない場合、2番目の選択肢である空のサブパターンは、対象の文字列と正常に一致します。

この方法はネガティブルックアヘッドよりも効率的ではありませんが、誰かが気の利いたものを見つけて、他のより興味深いアプリケーションでの使用を見つけた場合に備えて、ここでそれを投げると思いました。


0

より簡単な解決策は、not演算子を使用することです!

あなたの場合は文が一致する必要がありますし、「除外」と一致していない「が含まれて」。

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

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

RegExの設計者はnot演算子の使用を予想していたと思います。


0

たぶん、部分文字列を含まない(行全体ではなく)行のセグメントに一致できる正規表現を書き込もうとしているときに、Googleでこれを見つけることができます。理解するのにしばらくかかったので、共有します。

文字列を与える: <span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>

<span>「bad」というサブストリングを含まないタグに一致させたい。

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

ではConyEditは、コマンドラインを使用することができますcc.gl !/hede/正規表現のマッチングが含まれている、またはコマンドラインを使用していない行を取得するためにcc.dl /hede/正規表現のマッチングを含んで削除行にします。彼らは同じ結果を持っています。


0

文字列Xを含み、文字列Yも含まない行全体を照合する場合の例をもう1つ追加したいと思います。

たとえば、URL /文字列に「tasty-treats」が含まれているかどうかを確認したいとします。ただし、「chocolate」がどこにも含まれていない場合に限ります。

この正規表現パターンは機能します(JavaScriptでも機能します)

^(?=.*?tasty-treats)((?!chocolate).)*$

(例ではグローバルな複数行フラグ)

インタラクティブな例:https : //regexr.com/53gv4

マッチ

(これらのURLには「おいしいおやつ」が含まれており、「チョコレート」も含まれていません)

  • example.com/tasty-treats/strawberry-ice-cream
  • example.com/desserts/tasty-treats/banana-pudding
  • example.com/tasty-treats-overview

一致していません

(これらのURLにはどこかに「チョコレート」が含まれているため、「おいしいおやつ」が含まれていても一致しません)

  • example.com/tasty-treats/chocolate-cake
  • example.com/home-cooking/oven-roasted-chicken
  • example.com/tasty-treats/banana-chocolate-fudge
  • example.com/desserts/chocolate/tasty-treats
  • example.com/chocolate/tasty-treats/desserts
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.