2013-07-12 21 views
0

我正在实现一个多范围验证程序,该验证程序一次验证针对多个范围的用户输入。设置符号样式范围验证程序的正则表达式

如果我定义范围[1.5,4] | [6.9,9.3)| [10,11],它会像:从1到4,或从6到9不包括在内。 在这种情况下,数字5,9.3,13将不会被包含在这个范围内,但是数字2,7和10会是。

表达可以有多达范围尽可能的方式格式化的:

[或(

浮点数或整数

浮点数或整数

]或)

表达式语法

本质上,此范围表达由:

'[' 的范围包含起始

“]的范围包括端

'(' EXLUSIVE的范围

开始' '

')'范围的独占范围

','值分隔符

'|' OR语句

现在,我需要一种方法来验证用户已经写入了正确的范围表达式。如果解析器读取格式不正确的表达式,解析器将抛出异常。我想创建一个正则表达式来非常优雅地验证用户输入的表达式。我对正则表达式的体验并不那么宽泛,这似乎是一个很难做到的。我会喜欢一些关于如何构建像这样的整数,双精度,'['等复杂正则表达式的指南。

尽管正则表达式是平台不可知的,但我正在使用.NET。

+0

只是一个想法 - 我倾向于不喜欢“不这样做”作为对问题的回答 - 但是:既然你说“如果解析器读取格式不正确的表达式,[它]会抛出异常” - 如果可能的话,IMO的最佳方法是让解析器完成它的工作,捕获异常并将其用作验证结果,而不是执行自己的正则表达式,这可能实际上最终会导致s解析器的东西无论如何都会失败。话虽如此,我会看看(如果有人不打我的话)。 – JimmiTh

+0

@JimmiTh - 我认为OP基本上希望将表达式“编译”为正则表达式。也许我读错了? – JDB

+0

如果我理解正确,那么你正在尝试做的事情会导致一个可怕的丑陋和无效的正则表达式。请参阅http://stackoverflow.com/q/17604016/211627。另外,正则表达式是平台不可知的,就像C++是平台不可知的一样......离“Hello world”太远而且你很快遇到了特定于平台的实现。 – JDB

回答

2

快速射击,自由间距,可能远没有效率(首先,因为单个范围会在发现后面没有'|'时使正则表达式回溯) - 请参阅下面的版本2,它是(我相信)更有效率:

^      # Start of string 
(?:     # Start group, non-capturing 
    [([]    # '(' or '[' 
    \s*    # optional whitespace 
    [0-9]+   # at least one digit 0-9 
    (?:\.[0-9]+)?  # optionally '.' followed by at least one digit 0-9 
    \s*    # optional whitespace 
    ,     # ',' 
    \s*    # optional whitespace 
    [0-9]+   # at least one digit 0-9 
    (?:\.[0-9]+)?  # optionally '.' followed by at least one digit 0-9 
    \s*    # optional whitespace 
    [)\]]    # ')' or ']' 

    \s*     # optional whitespace 
    \|     # '|' 
    \s*     # optional whitespace 
)*     # all the above may appear 0 or more times 

[([]     # The remainder is exactly the same as the group above, 
\s*     # used for a single range or the last range - 
    [0-9]+    # i.e., a range NOT followed by '|' - of a multi range. 
    (?:\.[0-9]+)? 
    \s* 
, 
    \s* 
    [0-9]+ 
    (?:\.[0-9]+)? 
    \s* 
[)\]] 
$      # end of string 

这将匹配例如:

[1.5, 3] 
[23.7, 3.70) 
[2.9 , 3]|[3,2) 
[1.5, 4] | [6.9, 9.3) | [10, 11] 
(1.5, 3] 
[23.7, 3.70) 
(1.5, 5.0) 

但不是:

[23.7, 3.70) | (7, 9) |  // trailing OR 
| [23.7, 3.7]    // leading OR 

注意,它并不能保证第二个数字实际上是高于第一。为此,我推荐将其留给/ a分析器 - 或者添加捕获组并在正则表达式之外处理它们。

VERSION 2

这应该是更有效的,由于较少回溯 - 它基本上改变从:

(任何数量的范围,随后的|),接着是一系列

...至:

的范围内,接着(任何数量的前面有范围的|)

ETA:为了解释,版本1开始时检查“的范围内,接着|”。

如果我们只有一个范围,那就是浪费时间。当它到达“|”它将重新开始,检查正则表达式的第二部分 - 即是否存在,而不是“所需的范围|”?

在版本2中,我们开始检查“范围”。这意味着,如果只有一个范围,它将成功,不会有任何回溯。如果我们给它一些乱码,例如hello,它会立即失败,因为它现在知道第一个字符必须([ - 它不是可选的。而在版本1中,由于第一部分是可选的,因此必须检查正则表达式的第二部分以确保失败。

在几乎所有其他情况下(我测试过)版本2匹配 - 或无法匹配 - 以较少的步骤。

这里,因为它基本上是相同的正则表达式与某些部分交换,我反而把一个例子匹配的评论:

^ 
[([]     # (
    \s*    # 
    [0-9]+    # 3 
    (?:\.[0-9]+)?  # .90 
    \s*    # 
,     # , 
    \s*    # 
    [0-9]+    # 43 
    (?:\.[0-9]+)?  # .2 
    \s*    # 
[)\]]    # ] 
        # 
(?:     # 
    \s*    # 
    \|     # | 
    \s*    # 
        # 
    [([]    # [ 
    \s*    # 
    [0-9]+   # 55 
    (?:\.[0-9]+)? # .20 
    \s*    # 
    ,     # , 
    \s*    # 
    [0-9]+   # 2 
    (?:\.[0-9]+)? # .91 
    \s*    # 
    [)\]]    #) 
)* 
$ 

比赛和非比赛应该是相同的版本1

+0

这是完美的。我的意图不是让正则表达式解析它,而是让正则表达式验证表达式。解析发生在稍后。 –

+0

这也是我学习正则表达式的坚实教育材料。 –

+1

是的,我在这个问题的评论中的观点确实是,你应该尽可能多地离开实际的解析器 - 可能甚至比这个正则表达式还要多。与IMO相同,最佳的正则表达式电子邮件验证是检查*有*后跟@,后跟* *,可选地带有“。”的最佳正则表达式电子邮件验证 - 并且不会检查任何其他内容。即'^。+ @。+ \ .. + $' - 甚至只是'^。+ @。+ $' – JimmiTh

1

如果您选择使用正则表达式来执行此操作,则必须描述与|分隔的所有可能性。这里第一个范围的例子(你可以很容易为其他范围的增加值):

@"1\.[5-9]|[23](?:\.[0-9])?|4" 

但最优雅的方式海事组织,是提取所有数字和测试他们的数字后。

+0

如果我有可变数量的范围,这将如何工作?我想创建这个,所以任何数量的范围都可以。 –

+0

我相信问题要求正则表达式来测试“输入是一个有效的说明符”,而不是“给定一个说明符,如何使用正则表达式来测试给定的输入是否在它内部”。 – zebediah49