将Perl正则表达式转换为等效的ECMAScript正则表达式

Convert Perl regular expression to equivalent ECMAScript regular expression

本文关键字:正则表达式 ECMAScript Perl 转换      更新时间:2023-10-16

现在我使用的是VC++2010,但VC++2010的syntax_option_type只包含以下选项:

static const flag_type icase = regex_constants::icase;
static const flag_type nosubs = regex_constants::nosubs;
static const flag_type optimize = regex_constants::optimize;
static const flag_type collate = regex_constants::collate;
static const flag_type ECMAScript = regex_constants::ECMAScript;
static const flag_type basic = regex_constants::basic;
static const flag_type extended = regex_constants::extended;
static const flag_type awk = regex_constants::awk;
static const flag_type grep = regex_constants::grep;
static const flag_type egrep = regex_constants::egrep;

它不包含perl_syntax_group(Boost Library有此选项)但是,我不想使用Boost库

有很多正则表达式是用Perl编写的,所以我想将现有的Perl正则表达式转换为ECMAScript(或VC++2010支持的任何一个)。转换后,我可以直接在VC++2010中使用等效的正则表达式,而无需使用第三方库。

一个例子:

const boost::tregex e(__T("\A(\d{3,4})[- ]?(\d{4})[- ]?(\d{4})[- ]?(\d{4})\z"));
const CString human_format = __T("$1-$2-$3-$4");
CString human_readable_card_number(const CString& s)
{
return boost::regex_replace(s, e, human_format);
}
CString credit_card_number = "1234567887654321";
credit_card_number = human_readable_card_number(credit_card_number);
assert(credit_card_number == "1234-5678-8765-4321");

在上面的示例中,我想做的是将eformat转换为ECMAScript样式的表达式。

是否可以找到一种通用方法将所有Perl正则表达式转换为ECMAScript样式?有什么工具可以做到这一点吗

任何帮助都将不胜感激!

对于要转换的特定正则表达式,ECMA正则表达式中的等效项为:

/^(d{3,4})[- ]?(d{4})[- ]?(d{4})[- ]?(d{4})$/

在这种情况下,A(在Perl正则表达式中)与^(在ECMA正则表达式中,)(匹配字符串的开头)具有相同的含义,而Z(在Perl regex中)与$(在ECMA-regex中,)具有相同含义(匹配字符串结尾)。请注意,如果启用多行模式,ECMA regex中^$的含义将更改为匹配行的开头和结尾。

ECMA正则表达式是Perl正则表达式的一个子集,因此,如果正则表达式在Perl正则表达式中使用独占功能,则很可能无法转换为ECMA正则函数。即使对于相同的语法,regex的两种方言之间的语法含义也可能略有不同,因此查看文档并比较用法总是明智的。

我只想说明ECMA正则表达式和Perl正则表达式之间的相似之处。什么是不相似的,但可转换的,我会尽我所能提到它。

ECMA-regex缺少与Unicode配合使用的功能,这迫使您查找代码点并将其指定为字符类。

根据Perl正则表达式的文档:

  • 修改器:
    • ECMA标准中只有igm,它们的行为与Perl中的相同
    • s点全修饰语可以在ECMA正则表达式中使用两个互补字符类来模拟,例如[Ss][Dd]
    • 无论如何都不支持xp标志
    • 我不知道是否有任何方法可以模拟其余部分(前缀和后缀修饰符)
  • 元字符:
    • 我对将与非元字符一起使用有点怀疑,该字符不会解析为任何特殊含义,但如果你不在不需要的地方转义,那应该没问题。ECMA中的.排除了更多的字符。其余部分在ECMA正则表达式中表现相同(m标志对^$的影响相同)
  • 定量器:贪婪和懒惰的行为应该是一样的。ECMA正则表达式中没有所有格行为
  • 转义序列:
    • ECMA正则表达式中没有aetnrf相同
    • 如果正则表达式具有cX,请查看文档-存在差异
    • xhh在ECMA正则表达式和Perl正则表达式中很常见(指定2个十六进制数字是最安全的,否则,您必须查阅文档,了解该语言将如何处理少于2个十六进位数字的情况)
    • uhhhh是ECMA正则表达式的专用功能,用于指定Unicode字符。Perl还有其他专用方式来指定字符,如x{}N{}o{}00
    • luLU是Perl正则表达式的专属
    • CCD_ 43和CCD_
    • Perl正则表达式中的八进制转义(少于3个八进制数字)可能会令人困惑。仔细检查上下文,阅读文档,和/或测试正则表达式,以确保您理解它在上下文中的作用,因为它可能是转义序列或反向引用
  • 字符类和其他特殊转义:
    • wWsSdD在ECMA正则表达式和Perl正则表达式中是等效的,如果假设US-ASCII。如果涉及Unicode,事情就会一团糟
    • ECMA正则表达式中没有POSIX字符类。使用上面的wsd或在字符类中指定自己
    • 反向引用基本相同,但我不知道它是否允许Perl和ECMA regex的反向引用超过9
    • 命名引用可以通过反向引用进行模拟
    • ECMA正则表达式不支持其余部分([]和前面提到的转义序列除外)
  • 断言:
    • bB在两种语言中都是等价的,因为它们是如何基于w定义的
  • 捕获组:分组()和反向引用相同。$n在替换字符串中用于支持对匹配文本的引用,也是一样的。本节的其余部分是Perl独有的功能
  • 引用元字符:(前面章节中已经提到的内容)
  • 扩展模式:
    • ECMA正则表达式不支持修改正则表达式中的标志。根据标志的内容,您可以重写正则表达式(s标志始终可以转换为ECMA正则表达式中的等效表达式)
    • Perl和ECMA之间只有(?:pattern)(非捕获组)、(?=pattern)(正向超前)和(?!pattern)(反向超前)是常见的
    • ECMA正则表达式中没有注释,因此可以忽略(?#text)
    • ECMA正则表达式中不支持Look behinds。Perl支持固定宽度的look-behind。在某些情况下,用Perl编写的带有正look-behind的regex可以通过使look-behead成为一个捕获组而转换为ECMA regex
    • 如前所述,命名模式可以转换为普通捕获组,并可以使用编号后的引用引用
    • 剩下的是Perl独有的功能
  • 特殊的回溯控制谓词:这是Perl独有的,我不知道它们做什么(以前从未接触过它们),更不用说转换了。最有可能的情况是,它们无论如何都是不可兑换的
  • 结论

    如果正则表达式充分利用Perl正则表达式的功能,或者达到Boost库支持的级别(例如递归正则表达式),则不可能将正则表达式转换为ECMA正则表达式。幸运的是,ECMA-regex涵盖了最常用的功能,因此regex很可能是可转换的。

    参考

    MDN 上的ECMA RegExp参考