正则表达式的继承者?

时间:2011-01-27 07:33:06

标签: regex

看一下SO上常见的一些正则表达式问题,在我看来,传统的正则表达式语法在很多领域都缺乏人们现在正在寻找它的任务。例如:

  • 我想匹配1到31之间的数字,我该怎么做?

通常的答案是不要使用正则表达式,使用正常的条件比较。如果你自己只得到这个数字就好了,但是当你想把这个数字作为一个更长的字符串的一部分来匹配时,那就不那么好了。为什么我们不能写\d{1~31}这样的内容,要么修改正则表达式来进行某种形式的计数,要么让正则表达式引擎在内部将其转换为[1-9]|[12]\d|3[01]

  • 如何匹配特定字符串的偶数/奇数次?

这导致了一个非常混乱的正则表达式,能够只做(mytext){Odd}会很棒。

  • 如何使用正则表达式解析XML?

We all know这是一个坏主意,但如果[^ ]运算符不仅限于一个字符,那么此类和类似任务会更容易。能够做<name>(.*)[^(</name>)]

真是太好了
  • 如何使用正则表达式验证电子邮件?

非常常见,但正确使用正则表达式非常复杂。如果可以使用{IsEmail}这样的语法,那么每个人都必须重新发明轮子。


我确信还有其他一些也很有用。我不太了解正则表达式的内部结构,知道这些实现有多么容易,或者甚至是否可能。实现某种形式的计数(解决前两个问题)可能意味着它不再是技术上的“正则表达式”,但它肯定会有用。

'regex 2.0'语法是否可取,技术上可行,是否有人在处理这样的事情?

5 个答案:

答案 0 :(得分:16)

我相信Larry Wall用Perl 6 regexes覆盖了这个。基本思想是用更有用的语法规则替换简单的正则表达式。它们更容易阅读,并且更容易将代码放入以确保您拥有多个匹配项。另外,您可以命名IsEmail之类的规则。我不可能在这里列出所有细节,但足以说,这听起来像你的建议。

以下是http://dev.perl.org/perl6/doc/design/exe/E05.html的一些示例:

匹配IP地址:

token quad {  (\d**1..3) <?{ $1 < 256 }>  }
$str ~~ m/ <quad> <dot> <quad> <dot> <quad> <dot> <quad> /;

匹配嵌套括号:

$str =~ m/ \(  [ <-[()]> + : | <self> ]*  \) /;

注释:

    $str =~ m/ <'('>                # Match a literal '('
               [                    # Start a non-capturing group
                    <-[()]> +       #    Match a non-paren (repeatedly)
                    :               #    ...and never backtrack that match
               |                    # Or
                    <self>          #    Recursively match entire pattern
               ]*                   # Close group and match repeatedly
               <')'>                # Match a literal ')'
             /;

答案 1 :(得分:16)

不要怪工具,责怪用户。

构建正则表达式以匹配字符串中的模式。 就是这样

这不是为了:

  • 整数验证
  • 标记语言解析
  • 非常复杂的验证(即:RFC 2822)
  • 完全字符串比较
  • 拼写纠正
  • 矢量计算
  • 遗传解码
  • 奇迹制作
  • 保存宝贝
  • 财务管理
  • 次原子分区
  • 磁通电容器激活
  • Warp core engage
  • 时间旅行
  • 头痛诱发 永远不要介意最后一个。似乎正则表达式非常适合于在不应该使用的情况下执行最后一项任务。

我们是否应该重新设计螺丝刀,因为它不能钉? ,请使用锤子。

只需使用适当的工具即可完成任务。停止使用正则表达式来处理他们不符合条件的任务。

  • 我想匹配1到31之间的数字,我该怎么做?
    使用您的语言结构尝试将字符串转换为整数并进行适当的比较。

  • 如何匹配特定字符串的偶数/奇数次?
    正则表达式不是字符串解析器。但是,如果只需要解析原始字符串的子部分,则可以使用正则表达式提取相关部分。

  • 如何使用正则表达式解析XML?
    你没有。根据需要使用XML或HTML解析器。此外,XML解析器不能完成HTML解析器的工作(除非你有一个完美形成的XHTML文档),反之亦然。

  • 如何使用正则表达式验证电子邮件?
    您可以使用this large abomination,也可以正确使用with a parser

答案 2 :(得分:5)

可能它已经存在并且很久以前了。它被称为“语法”。有没有听说过yacc和lex?现在需要一些简单的东西。可能看起来很奇怪,正则表达式的强大之处在于它们在现场编写非常简单。

我相信一些(但很大的)专业领域已经有了所需要的东西。我正在考虑使用XPath语法。

是否有更大的(不限于XML但仍然简单)替代方案可以覆盖所有情况?也许你应该看看perl 6 grammars

答案 3 :(得分:5)

所有这些在Perl中都是合理可行的。

将1..31与正则表达式匹配:

/( [0-9]+ ) (?(?{ $^N < 1 && $^N > 31 })(*FAIL)) /x

生成[1-9]|[12]\d|3[01]

之类的内容
use Regexp::Assemble qw( );
my $ra = Regexp::Assemble->new();
$ra->add($_) for (1..31);
my $re = $ra->re;                 # qr/(?:[456789]|3[01]?|1\d?|2\d?)/

Perl 5.10+使用尝试来优化替换,因此以下内容应该足够了:

my $re = join '|', 1..31;
$re = qr/$re/;

匹配偶数次出现次数:

/ (?: pat{2} )* /x

匹配奇数次发生:

/ pat (?: pat{2} )* /x

模式否定匹配:

/<name> (.*?) </name>/x  # Non-greedy matching

/<name> ( (?: (?!</name>). )* ) </name>/x

获取与电子邮件地址匹配的模式:

use Regexp::Common qw( Email::Address );
/$RE{Email}{Address}/

答案 4 :(得分:2)

没有。我们应该保留正则表达式。它们已经太复杂了。你最后一次认为自己已经钉了它的时候是什么时候,也就是说,你的内存中加载了整个扩展的正则表达式语法(选择你的风格)?

正则表达式背后的理论非常简单。但后来我们想要这个和那个一起去。该工具很有用,但不适用于非常规匹配。没关系!

大多数人都错过了,没有上下文的语法和很少的专业口译员都很容易写。

我们应该为我们选择的语言在标准库中支持解析器支持而不是使正则表达式变得更加困难!