2

だから私は次の正規表現を持っています:

(?<!\.)\b([\w\@\-]+) *\b(IN|NOT IN|LIKE|NOT LIKE|BETWEEN|REGEXP|NOT|IS|XOR)+\b *

これは、SQLコードと一致させるのに役立ちます。

ただし、2 番目の括弧内のフレーズ (「NOT IN」や「NOT LIKE」など) には問題があるようです。

一致するか一致しない正規表現が必要です (現在の正規表現のように部分一致はありません)。

  1. customers.id NOT IN (SELECT MAX(customers_service.customer_id))絶対に合わせてはいけない
  2. customers.id NOT LIKE (SELECT MAX(customers_service.customer_id))絶対に合わせてはいけない
  3. id NOT IN (SELECT MAX(customers_service.customer_id))一致する必要があります
  4. id IN (SELECT MAX(customers_service.customer_id))一致する必要があります

チェックに RegexBuddy を使用していましたが、正規表現を使用して No. 1 と No. 2 の一致を取得しました。

また、

  1. id NOT IN (SELECT MAX(customers_service.customer_id))id NOTとは対照的に、のみに一致しますid NOT IN
  2. id NOT LIKE (SELECT MAX(customers_service.customer_id))id NOTとは対照的に、のみに一致しますid NOT LIKE

この正規表現を変更して、否定的な後読みの条件と、2 番目のブラケット内の正確なフレーズをキャプチャするか、まったく一致しない (部分一致しない) ようにします。

どうすればこれを行うことができますか?

4

3 に答える 3

2

まず、\b単語の先頭または末尾と一致しません。いつもそう言われますが、嘘です。\b一致するのは、単語の文字が後に続くが、(?=\w)(?<!\w)単語の文字がない-- または、単語の文字が前にあり、に単語の文字がない--の位置です(?<=\w)(?!\w)。これらの条件が一致させたいものと正確に一致しない場合は、おそらくまったく使用しない方がよいでしょう\b

一致させようとしている名前には、標準の「単語」文字 (文字、数字、アンダースコア) だけでなく も含まれている可能性があるため、単語の境界は役に立ちません@-一般に、単語を完全に一致させるには、否定後読みと否定先読みを使用します。

(?<![\w@-])[\w@-]+(?![\w@-])

あなたの場合、の文字が ではないことも確認したい.ので、の文字は空白でなければならないことがわかっているので、正規表現の一部は次のようになります。

(?<![.\w@-])[\w@-]+\s+

より大きな問題は、これが望まないものにも一致する可能性があることです。つまり、NOTやなどのキーワードINです。2つの対策を提案します。NOT INまず、キーワードの正規表現を強化して、とのような複合キーワードNOT LIKEが原子単位として扱われるようにします。

(?:NOT(?:\s+(?:IN|LIKE))?|IN|LIKE|BETWEEN|REGEXP|IS(?:\s+NOT)?|XOR)\b

次に、これを先読みで使用して、一致する最初の単語がキーワード (の一部) ではないことを確認します。読みやすくするために 2 行に分けた完全な正規表現を次に示します。

(?<![.\w@-])(?!(?:NOT(?:\s+(?:IN|LIKE))?|IN|LIKE|BETWEEN|REGEXP|IS|XOR)\b)[\w@-]+\s+
(?:NOT(?:\s+(?:IN|LIKE))?|IN|LIKE|BETWEEN|REGEXP|IS|XOR)\b\s*

キーワードのサブルーチン グループを定義することで、保守を容易にすることができます。PHP 文字列リテラルとしては、次のようになります。

'~
(?(DEFINE)(?<KEYWORD>
  (?:NOT(?:\s+(?:IN|LIKE))?|IN|LIKE|BETWEEN|REGEXP|IS(?:\s+NOT)?|XOR)\b
))
(?<![.\w@-])(?!(?&KEYWORD))[\w@-]+\s+(?&KEYWORD)\s*
~ix'

...そしてここにデモがあります。

于 2012-12-30T06:44:05.457 に答える
0

わかりました。したがって、多くの「正規表現」の後、これが私のためにトリックを行った正規表現です。

(?<=\s)(?!(?:not|is)(?=\s))([\w\@\-]+)(?=\s) (?<=\s)(NOT LIKE|NOT IN|IS NOT|BETWEEN|REGEXP|LIKE|XOR|NOT|IN|IS)(?=\s)

もちろん、私のpreg関数では、大文字と小文字を区別しないパターン修飾子を使用します。

ここ StackOverflow に投稿した他の質問から他の部分を見つける必要がありました。

乾杯。

于 2012-12-29T16:46:01.877 に答える
0

あなたの言葉遣いは少し混乱していますが、私が理解しているように、否定的な後読みは期待どおりに機能しています。

「部分一致」の問題については、キーワードを長さの短い順に並べる必要があります。

(?<!\.)\b([\w\@\-]+) *\b(NOT LIKE|BETWEEN|REGEXP|NOT IN|LIKE|NOT|IN|IS|XOR)+\b *

このようにして、短いキーワードに落ち着く前に、「より完全な」キーワードを取得しようとします。

編集

何が起こっているかわかりました。の場合

customers.id NOT IN (SELECT MAX(customers_service.customer_id))

一致する理由は、によってNOT一致されており、演算子として一致しているからです。つまり、列名だと思います。(?<!\.)\b([\w\@\-]+)INNOT

これを回避する唯一の方法は、制約を追加することです。たとえば、文字列が常にテーブル/列識別子で始まることがわかっている場合は、次のようにします。

^\s+([\w\@\-]+) *\b(NOT LIKE|BETWEEN|REGEXP|NOT IN|LIKE|NOT|IN|IS|XOR)+\b *
****

このように、後読みも単語境界も必要ありません。

ただし、その制約を作成できない場合は、完全に非現実的ではないにしても、注意が必要です (基本的に正規表現から SQL パーサーを構築する必要があるため)。重要なのは、識別子と演算子を区別する何らかの方法を正規表現に与えることです。そうでなければ、それはわかりません。すべての識別子が小文字であることがわかっている場合は、薄っぺらではありますが、目的には合うかもしれません。

于 2012-12-28T16:27:22.920 に答える