3

ループして、他の2つの特定の文字列の間に特定の文字列を持たないすべてのファイルを見つける必要がある一連のファイルがあります。どうやってやるの?

私はこれを試しましたが、うまくいきませんでした:

grep -lri "\(stringA\).*\(?<!stringB\).*\(stringC\)" ./*.sql

編集: ファイルは次のような構造を持つことができます:

StringA
StringB
StringA
StringC

私が知りたいのは、文字列 A と文字列 C の間に文字列 C がない場所があるかどうかを知ることだけです。

4

3 に答える 3

2

-Lのオプションを使用して、grep一致しないすべてのファイルを印刷し、特定の文字列の組み合わせを探すことができます。

grep -Lri "\(stringA\).*\(stringB\).*\(stringC\)" ./*.sql
于 2013-02-28T16:31:44.247 に答える
2

簡単な答えは次のとおりです。

grep "abc[^(?:def)]*ghi" ./testregex

これは、次のような testregex ファイルに基づいています。

abcghiabc
abcdefghi
abcghi

出力は次のようになります。

$ grep "abc[^(?:def)]*ghi" ./testregex 
abcghiabc
abcghi

あなたのユースケースにマッピングすると、これは大まかに次のように翻訳されると思います:

grep -lri "stringA[^(?:stringB)]*stringC" ./*.sql

各文字列の間の「.*」を削除したことに注意してください。これは、除外しようとしている文字列と一致するためです。

更新: 元の質問で改行が呼び出されるようになったため、grep の -z フラグを使用します。

-z

行末の改行を抑制し、ヌル文字に置き換えます。つまり、grep は行末がどこにあるかを認識していますが、入力を 1 つの大きな行として認識します。

したがって:

grep -lriz "stringA[^(?:stringB)]*stringC" ./*.sql

私が最初にこのアプローチを自分で使用しなければならなかったとき、次の説明を書きました...

具体的には、「任意の文字、任意の回数、貪欲でない(したがって、後続の明示的なパターンに従う)、および SEQUENCE /> に一致しない」と一致させたいと考えていました。

最後の部分は、私が共有するために書いていることです:「シーケンス /> と一致しません」。「任意の文字」ロジックと組み合わせた文字シーケンスを使用したのはこれが初めてです。

私のターゲット文字列:

<img class="photo" src="http://d3gqasl9vmjfd8.cloudfront.net/49c7a10a-4a45-4530-9564-d058f70b9e5e.png" alt="Iron or Gold" />

私の最初の試み:

<img.*?class="photo".*?src=".*?".*?/>

これはオンライン正規表現テスターでは機能しましたが、実際の Java コード内で何らかの理由で失敗しました。試行錯誤の結果、すべての「。?」を置き換えることがわかりました。「[^<>] ?」で 成功しました。つまり、「任意の文字の非貪欲なマッチング」の代わりに、「< または > を除く任意の文字の非貪欲なマッチング」を使用できます。

しかし、これらの文字を含む代替テキストを見たことがあるので、これを使用したくありませんでした。私の特定のケースでは、文字シーケンス「/>」を除外シーケンスとして使用したいと考えていました。そのシーケンスが検出されたら、「任意の文字」の一致を停止します。

これは私のレッスンに私をもたらします:

パート 1: 文字シーケンスは (?:regex) を使用して実現できます。つまり、() 括弧を通常どおり文字シーケンスに使用しますが、シーケンスがターゲット グループとして一致しないようにするために、先頭に「?:」を追加します。したがって、"(?:/>)" は "/>" に一致し、"(?:/>)*" は "/>/>/>/>" に一致します。

パート 2: このような文字シーケンスは、単一の文字と同じ方法で使用できます。つまり、「[^(?:/>)]*?」です。シーケンス「/>」を除く任意の文字に何度でも一致し、貪欲ではありません。

それだけです。検索のキーワードは、「非キャプチャ グループ」と「負の先読み|後読み」です。後者の機能は、これまで行ってきたよりもはるかに深く、まだ理解していないフラグが追加されています。しかし、最初の理解により、当面のタスクに必要なツールが得られました。これは、私がしばらく疑問に思っていた機能です。あなたのツールセットで離れて。

于 2013-02-28T16:28:13.403 に答える
0

DreadPirateShawn によって提供されたステートメントをいじった後:

stringA[^(?:stringB)]*stringC

本当に有効な正規表現ではないことがわかりました。このステートメントは、文字列全体ではなく、指定されたセット内のすべての文字を除外していました。ということで掘り続けました。

グーグルでパターンをテストした後、次のステートメントを思いつきました。これは私のニーズに合っているようです。

stringA\s*\t*(?:(?!stringB).)*\s*\t*stringC

このパターンは、指定された 2 つの文字列の間の指定された文字列を除くすべてのテキストに一致します。また、空白文字も考慮されます。

さらにテストを行う必要がありますが、このパターンは私の要件に完全に適合しているようです

更新:これは私にとってうまくいくと思われる声明の最終版です:

grep -lriz "(set feedback on){0,}[ \t]*(?:(?!set feedback off).)*[ \t]*select sysdate from dual"  ./*.sql
于 2013-03-05T15:31:28.363 に答える