繁体   English   中英

正则表达式是否可以匹配字符串开头或结尾的字符(但不能同时匹配)?

[英]Can a regular expression match a character at the beginning OR end of the string (but not both)?

我正在写一个正则表达式来验证欧元货币字符串。 它允许几种不同的格式,因为一些语言环境使用小数点作为千位分隔符,一些使用空格,一些将€放在开头,一些放在最后。 这是我想出的:

/^(€ ?)?\\-?([1-9]{1,3}( \\d{3})*|[1-9]{1,3}(\\.\\d{3})*|(0|([1-9]\\d*)?))(,[0-9]{2})?( ?€)?$/

这适用于以下测试:

有效:

123 456,78
123.456,78
€6.954.231
€896.954.231
16.954.231€
12 346 954 231€
€10.03
10.03
1,39
,03
0,10
€10567,01
€0,01
€1 234 567,89
€1.234.567,89

无效

1,234€1,1
50#,50
123,@€
€€500
0001
€,001
€0.001
12.34,56
123456.123.123456

这样做的一个问题是它验证了两端带有欧元符号的字符串,例如€123€。 这对我的目的来说可能是可以接受的,但是有没有办法制作一个紧凑的RegEx,它只允许一端的字符,而不是两者,或者我只需要编写一个两倍长的字符,首先检查一个有效的字符串开头是可选的€,然后是最后一个带有可选€的有效字符串?

更新接受答案中的答案仍有一些误报。 我最终编写了一个函数,它有几个选项来自定义验证器。 这是该库中isCurrency函数。 仍然使用前瞻来避免某些边缘情况,这是回答这个问题的关键。

有了先行,这将起作用

^(?!€*$)(€ ?(?!.*€)(?=,?\d))?\-?([1-9]{1,3}( \d{3})*|[1-9]{1,3}(\.\d{3})*|(0|([1-9]\d*)?))(,[0-9]{2})?( ?€)?$

请参阅: https//regex101.com/r/aR4xR8/8

@Necreaux值得称赞,首先指出前瞻!

根据您的正则表达式引擎,您可以使用负向前导来执行此操作。

^€(?!(.*€))

您可以使用此模式:

^
(?=(.))          # you capture the first character in a lookahead
(?:€[ ]?)?
(?:
    [1-9][0-9]{0,2}
    (?:
        ([ .]) [0-9]{3} (?: \2 [0-9]{3})*
      |
        [0-9]*
    )
    (?:,[0-9]{2})?
  |
    0?,[0-9]{2}
)

(?:
    [ ]?
    (?!\1)€   # you test if the first character is not an €
)?
$

在线演示

我们的想法是捕获第一个字符并测试它最后是否相同。

要与javascript一起使用,您需要删除格式:

var re = /^(?=(.))(?:€ ?)?(?:[1-9][0-9]{0,2}(?:([ .])[0-9]{3}(?:\2[0-9]{3})*|[0-9]*)(?:,[0-9]{2})?|0?,[0-9]{2})(?: ?(?!\1)€)?$/;

关于这种方式:唯一的兴趣是短缺。 如果你想要性能,最好的方法是从字面上写出两种可能性:

var re = /^(?:€ ?(?:[1-9][0-9]{0,2}(?:([ .])[0-9]{3}(?:\1[0-9]{3})*|[0-9]*)(?:,[0-9]{2})?|0?,[0-9]{2})|(?:[1-9][0-9]{0,2}(?:([ .])[0-9]{3}(?:\2[0-9]{3})*|[0-9]*)(?:,[0-9]{2})?|0?,[0-9]{2})(?: ?€)?)$/;

写入时间更长,但它减少了正则表达式引擎的工作。

使用支持PCRE等条件子模式的正则表达式引擎,您可以这样写:

\A
(€ ?)?
(?:
    [1-9][0-9]{0,2}
    (?: ([ .]) [0-9]{3} (?:\2[0-9]{3})* | [0-9]*)
    (?:,[0-9]{2})?
  | 
    0?,[0-9]{2}
)
(?(1)| ?€)
\z

其中(?(1)| ?€)if..then..else(?(condition)true|false) ,用于检查是否定义了捕获组1。

你可以将你的正则表达式分成两个派对并将它们与'|'结合起来。 最后一个用€和另一个用于€的东西。

/(^(€ ?)?\-?([1-9]{1,3}( \d{3})*|[1-9]{1,3}(\.\d{3})*|(0|([1-9]\d*)?))(,[0-9]{2})?$)|(^\-?([1-9]{1,3}( \d{3})*|[1-9]{1,3}(\.\d{3})*|(0|([1-9]\d*)?))(,[0-9]{2})?( ?€)?$)/

编辑:

我错过了你的最后一句话。 我认为最简单的是将正则表达式编写两次。

这是我能够来的最接近的。 它使用负向前瞻来确保字符串不以欧元符号开头和结尾:

^(?!€.*€$)€?\s*(0|[1-9][0-9]{0,2})?([. ]?[0-9]{3})*(,[0-9]{2})?\s*€?$

有关完整说明和示例, 请参阅此处的Regex 101 Demo 正如你所看到的,它通过了你所有的测试,但它让一些不好的测试通过了。 我确定数字部分可以调整,以便它适合你。 确保没有两个欧元符号的部分就是这样:

^(?!€.*€$)€?\s*<digit validation goes here>\s*€?$

负向前瞻确保字符串不以欧元符号开头和结尾,然后在开始时检查可选的欧元符号,后跟任意数量的空格,验证数字,然后检查任意数量的空格和欧元符号在末尾。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM