4

始める前に、これを行う正規表現よりも優れた方法があることを知っています(トークナイザーなど)。それは問題の内容ではありません。私はすでに正規表現を使用して立ち往生しており、アドバイスが必要な1つの特別な場合を除いて、必要に応じてすでに機能しています。

JavaScriptのようなコードをスキャンしてnew、すべてのオブジェクト宣言の前にキーワードを挿入する必要があります。このキーワードを必要とするすべてのオブジェクトの名前はすでに知っていますが、開始する前にコードにそのキーワードが含まれることはないことを知っています(したがって、繰り返されるnew単語を処理したり、何かがオブジェクトであるかどうかを推測したりする必要はありませんたとえば、一般的な行は次のようになります。

foo = Bar()

私がすでに知っているところでは、それBarは「クラス」であり、オブジェクト宣言には「new」が必要です。次の正規表現でうまくいきます。

for classname in allowed_classes:
    line = re.sub(r'^([^\'"]*(?:([\'"])[^\'"]*\2)*[^\'"]*)\b(%s\s*\()' % classname, r'\1new \3', line)

それは魅力のように機能しclassname、文字列の中にあるときは触れないようにします(正規表現の最初の部分は、事前に偶数の引用符があることを確認するように指示しています-ネストされた状態で壊れてしまうという点で少しナイーブです引用符ですが、その場合を処理する必要はありません)。問題は、クラス名も$それらに含まれる可能性があることです。$Barしたがって、 allowed_classesに存在する場合は、次の行も許可されます。

foo = $Bar()

上記の正規表現は、ドル記号のために無視されます。エスケープすることでうまくいくと思いましたが、このロジック$Barは、クラスの1つであっても、上記の行には影響しないようです。

for classname in allowed_classes:
    line = re.sub(r'^([^\'"]*(?:([\'"])[^\'"]*\2)*[^\'"]*)\b(%s\s*\()' % re.escape(classname), r'\1new \3', line)

手で逃げてみまし\たが、効果もありません。$誰かがへの変換が機能しない理由\$とそれを修正できるものを説明できますか?

ありがとう

4

1 に答える 1

9

現在の正規表現が機能しない理由は\b、クラス名の直前にあるためです。 \b単語の境界に一致するため、単語の文字と単語以外の文字の間でのみ一致します。文字列foo = Bar()の場合、\bはスペースと。の間で一致しますBが、の場合、スペースと。は両方とも単語以外の文字であるため、一致foo = $Bar()する\bことはできません$

これを修正するには、に変更\b(?=\b|\B\$)ます。結果の正規表現は次のとおりです。

for classname in allowed_classes:
    line = re.sub(r'^([^\'"]*(?:([\'"])[^\'"]*\2)*[^\'"]*)(?=\b|\B\$)(%s\s*\()' % classname, r'\1new \3', line)

先読みを使用することにより、次の両方のケースを処理できます。

  • classnameで始まらない$ので、一致させる前に単語の境界が必要です。先読みclassnameの内部でこれを処理します\b
  • classnameで始まる$ので、次の文字がaの場合は$一致させます。\B\$前の文字が単語文字でない場合にのみ一致するように使用しました$が、有効なJSコードが考えられないため、これはおそらく不要です。
于 2012-12-02T23:39:56.657 に答える