5

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

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 库有选项)。但是,我不想使用 Boost Library。

有很多用 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");

在上面的例子中,我想做的是转换和e样式表达式。formatECMAScript

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

任何帮助将不胜感激!

4

1 回答 1

5

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

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

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

ECMA regex 是 Perl regex 的子集,因此如果 regex 使用 Perl regex 中的专有功能,它很可能无法转换为 ECMA regex。即使对于相同的语法,两种正则表达式方言之间的语法可能意味着略有不同,因此检查文档并比较用法总是明智的。

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

ECMA 正则表达式缺乏与 Unicode 一起使用的功能,这迫使您查找代码点并将它们指定为字符类。

根据Perl 正则表达式的文档

  • 修饰符:
    • 只有i, g,m在 ECMA 标准中,它们的行为与在 Perl 中相同。
    • sdot-all 修饰符可以在 ECMA 正则表达式中通过使用 2 个互补字符类来模拟,例如[\S\s][\D\d]
    • 无论如何都不支持xp标志。
    • 我不知道是否有任何方法可以模拟其余部分(前缀和后缀修饰符)。
  • 元字符:
    • \我对使用无法解决任何特殊含义的非元字符有点怀疑,但如果你不在不需要的地方逃跑应该没问题。.在 ECMA 中排除了更多字符。其余部分在 ECMA 正则表达式中的行为相同(甚至m标志对^and的影响$)。
  • 量词:
    • 贪婪和懒惰的行为应该是相同的。ECMA 正则表达式中没有占有行为。
  • 转义序列:
    • ECMA 正则表达式中没有\aand \e\t, \n, \r,\f是一样的。
    • 如果正则表达式有,请检查文档\cX- 存在差异。
    • \xhh在 ECMA 正则表达式和 Perl 正则表达式中很常见(指定 2 个十六进制数字是最安全的 - 否则,您将不得不查看文档以了解该语言将如何处理少于 2 个十六进制数字的情况)。
    • \uhhhh是 ECMA 正则表达式的专有功能,用于指定 Unicode 字符。Perl 有其他专有的方法来指定字符,例如\x{}, \N{}, \o{}, \000
    • \l, \u, \L,\U是Perl 正则表达式独有的。
    • \Q并且\E可以通过手动转义引用的部分来模拟。
    • Perl 正则表达式中的八进制转义(少于 3 个八进制数字)可能会令人困惑。仔细检查上下文,阅读文档,和/或测试正则表达式以确保您了解它在上下文中所做的事情,因为它可能是转义序列或反向引用。
  • 字符类和其他特殊转义:
    • \w, \W, \s, \S, \d,\D在 ECMA 正则表达式和 Perl 正则表达式中是等价的,如果假设是 US-ASCII 的话。如果涉及 Unicode,事情将一团糟。
    • ECMA 正则表达式中没有 POSIX 字符类。使用上面\w\s,\d或在字符类中指定自己。
    • 反向引用基本相同 - 但我不知道它是否允许 Perl 和 ECMA 正则表达式的反向引用超过 9。
    • 命名引用可以用反向引用来模拟。
    • 其余的(除了[]已经提到的转义序列)在 ECMA 正则表达式中不受支持。
  • 断言:
    • \b并且\B在两种语言中是等价的,关于它们是如何基于\w.
  • 捕获组:分组()和反向引用是相同的。$n,在替换字符串中用于反向引用匹配的文本,是相同的。本节中的其余部分是 Perl 独有的功能。
  • 引用元字符:(前几节中已经提到的内容)。
  • 扩展模式:
    • ECMA 正则表达式不支持修改正则表达式中的标志。根据标志是什么,您可能能够重写正则表达式(s标志是始终可以转换为 ECMA 正则表达式中的等效表达式的表达式)。
    • Perl 和 ECMA 之间只有(?:pattern)(non-capturing group), (?=pattern)(positive look ahead), (negative look ahead) 是通用的。(?!pattern)
    • ECMA 正则表达式中没有注释,所以(?#text)可以忽略。
    • ECMA 正则表达式不支持后视。Perl 支持固定宽度的look-behind。在某些情况下,用 Perl 编写的正则表达式可以转换为 ECMA 正则表达式,方法是使后视图成为一个捕获组。
    • 如前所述,命名模式可以转换为正常的捕获组,并且可以通过编号的反向引用进行引用。
    • 其余的是 Perl 独有的特性。
  • 特殊回溯控制动词:这是 Perl 独有的,我不知道这些是做什么的(以前从未接触过它们),更不用说转换了。最有可能的情况是它们无论如何都不能转换。

结论

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

参考

MDN 上的 ECMA RegExp 参考

于 2012-08-26T03:59:00.577 回答