単語を一致させてから、他のツール(例)を使用して一致を逆にすることが可能であることを私は知っていますgrep -v
。hede
ただし、正規表現を使用して、特定の単語を含まない行を照合することは可能ですか?
入力:
hoho
hihi
haha
hede
コード:
grep "<Regex for 'doesn't contain hede'>" input
必要な出力:
hoho
hihi
haha
単語を一致させてから、他のツール(例)を使用して一致を逆にすることが可能であることを私は知っていますgrep -v
。hede
ただし、正規表現を使用して、特定の単語を含まない行を照合することは可能ですか?
hoho
hihi
haha
hede
grep "<Regex for 'doesn't contain hede'>" input
hoho
hihi
haha
正規表現が逆マッチングをサポートしていないという概念は完全には真実ではありません。ネガティブルックアラウンドを使用して、この動作を模倣できます。
^((?!hede).)*$
非キャプチャバリアント:
^(?:(?!: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"
grepに使用しているだけの場合grep -v hede
は、hedeを含まないすべての行を取得するために使用できます。
ETAああ、質問を読み直すと、grep -v
おそらく「ツールオプション」が意味するものです。
答え:
^((?!hede).)*$
説明:
^
文字列の先頭
(
を \1 にグループ化してキャプチャし (0 回以上 (可能な限り多く一致する))、
(?!
存在しないかどうかを先読みし、
hede
あなたの弦、
)
オプションの \n の前に、先読みの
終わり、 .
\n 以外の任意の文字
)*
、\1 の終わり (注: このキャプチャで量指定子を使用しているため、キャプチャされたパターンの最後の繰り返しのみが \1 に格納されます) 、
$
そして文字列の終わり
与えられた答えはまったく問題ありませんが、学術的なポイントです:
理論的なコンピューター サイエンスの意味での正規表現は、このようにすることはできません。彼らにとって、それは次のように見えなければなりませんでした:
^([^h].*$)|(h([^e].*$|$))|(he([^h].*$|$))|(heh([^e].*$|$))|(hehe.+$)
これは完全な一致のみを行います。サブマッチでそれを行うと、さらに厄介になります。
文字列全体が一致する場合にのみ正規表現テストを失敗させたい場合は、次のようにします。
^(?!hede$).*
例 -- 「foo」以外のすべての値を許可する場合 (つまり、「foofoo」、「barfoo」、および「foobar」はパスしますが、「foo」は失敗します)、次を使用します。^(?!foo$).*
もちろん、正確な等価性をチェックしている場合、この場合のより良い一般的な解決策は、文字列の等価性をチェックすることです。
myStr !== 'foo'
正規表現機能が必要な場合は、否定をテストの外に置くこともできます(ここでは、大文字と小文字の区別と範囲の一致)。
!/^[a-f]oo$/i.test(myStr)
ただし、この回答の上部にある正規表現ソリューションは、(おそらく API によって) 正の正規表現テストが必要な状況で役立つ場合があります。
これは、任意の正規表現を否定するのが簡単ではない理由の良い説明です。ただし、他の回答には同意する必要があります。これが仮説的な質問以外の場合、ここでは正規表現は適切な選択ではありません。
否定先読みを使用すると、正規表現は特定のパターンを含まないものと一致できます。これは 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()
);
提示されたオプションのいくつかを評価し、それらのパフォーマンスを比較し、いくつかの新しい機能を使用することにしました。.NET 正規表現エンジンでのベンチマーク: http://regexhero.net/tester/
最初の 7 行は検索された Expression を含んでいるため一致しませんが、下の 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 のソリューションは、さらに高速で読みやすいものにすべきだと思います。
正規表現ではありませんが、パイプでシリアル 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 のロジックは (コメントではありません) and (matches dir) です。
前述(?:(?!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
これが私がそれを行う方法です:
^[^h]*(h(?!ede)[^h]*)*$
他の回答よりも正確で効率的です。Friedl の「ループ展開」効率化手法を実装しており、必要なバックトラッキングがはるかに少なくなります。
文字クラスを否定するのと同様の単語を否定するために文字を一致させたい場合:
たとえば、文字列:
<?
$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"
TagOPは、正規表現が使用されるコンテキスト(プログラミング言語、エディター、ツール)を示すために、 または投稿を指定しませんでした。
私にとっては、を使用してファイルを編集しているときに、これを行う必要がある場合がありますTextpad
。
Textpad
一部の正規表現をサポートしていますが、先読みまたは後読みをサポートしていないため、いくつかの手順が必要です。
string を含まないすべての行を保持し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. この時点で、一意の「Tag」で始まるすべての行には、文字列が含まれていません
hede
。私は今、それらの行だけに何か他のことをすることができます.
4. 完了したら、一意の「タグ」をすべての行から削除します (置換文字列は空です)。
Search string:<@#-unique-#@>
Replace string:<nothing>
Replace-all
PCRE動詞を通して(*SKIP)(*F)
^hede$(*SKIP)(*F)|^.*$
これにより、正確な文字列を含む行が完全にスキップされhede
、残りのすべての行に一致します。
パーツの実行:
上記の正規表現を 2 つの部分に分割して考えてみましょう。
|
記号の前の部分。パーツを一致させてはなりません。
^hede$(*SKIP)(*F)
|
記号の後の部分。パーツを一致させる必要があります。
^.*$
パート1
正規表現エンジンは最初の部分から実行を開始します。
^hede$(*SKIP)(*F)
説明:
^
私たちがスタート地点にいることを主張します。hede
文字列に一致hede
$
行末にいることをアサートします。したがって、文字列を含む行hede
が一致します。正規表現エンジンが次の(*SKIP)(*F)
(注: You could write (*F)
as(*FAIL)
) 動詞を検出すると、スキップして一致を失敗させます。|
変更と呼ばれる、または論理 OR 演算子が PCRE 動詞の隣に追加され、すべての境界に一致します。ただし、行に正確な文字列が含まれている場合を除き、すべての行のすべての文字の間に存在しますhede
。ここでデモを参照してください。つまり、残りの文字列の文字を照合しようとします。これで、2 番目の部分の正規表現が実行されます。
パート2
^.*$
説明:
^
私たちがスタート地点にいることを主張します。つまり、行内の行頭を除くすべての行頭に一致しますhede
。ここでデモを参照してください。.*
複数行モードで.
は、改行文字またはキャリッジ リターン文字を除く任意の文字に一致します。また*
、前の文字を 0 回以上繰り返します。したがって.*
、行全体に一致します。ここでデモを参照してください。
なぜ .+ の代わりに .* を追加したのですか?
.*
空白行には一致しますが、空白には一致しないため.+
です。を除くすべての行に一致させたいのですがhede
、入力にも空白行が含まれる可能性があります。.*
の代わりに使用する必要があります.+
。.+
前の文字を 1 回以上繰り返します。ここ.*
で空白行に一致するを参照してください。
$
ここでは行末アンカーは必要ありません。
以下の関数は、目的の出力を得るのに役立ちます
<?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;
}
?>