4

在我开始之前,我知道有比正则表达式更好的方法(比如标记器),这不是问题所在。我已经被正则表达式卡住了,它已经可以按我的需要工作了,除了一种特殊情况,这是我需要建议的。

我需要浏览一些类似 JavaScript 的代码,并new在每个对象声明前插入关键字。我已经知道需要这个关键字的所有对象的名称,并且我知道在我开始之前它们都不会在代码中包含那个关键字(所以我不需要处理重复的new单词或猜测某物是否是一个对象与否。例如,典型的行可能如下所示:

foo = Bar()

我已经知道这Bar是一个“类”并且需要“新”来进行对象声明。以下正则表达式可以解决问题:

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是其中一个类,这个逻辑似乎也对上面的行没有影响:

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 回答