输出第一个与正则表达式不匹配的字符。

3

是否可以输出与正则表达式不匹配的字符串(其索引)中的第一个字符?是否可以仅使用正则表达式匹配操作或必须使用更复杂的操作?

例如,在JavaScript中,我有一个正则表达式/^\d{3}\s\d{2}$/,它匹配具有3个数字后跟一个空格和另外2个数字的字符串。我有一个字符串"123a45",我将这个正则表达式应用于它。这样做(例如,"123a45".match(/^\d{3}\s\d{2}$/))返回null,因为正则表达式没有匹配。如何获取导致此不匹配的第一个字符(在本例中为"a",索引为3的字符)?

其中一个用例是直接指向用户输入的字符串中根据用于验证的某些正则表达式无效的字符。


4
广义问题可能无法解决(例如带有 OR | 的正则表达式,您不知道实际导致问题的字符是哪一个,因为有两种可能情况)。对于某些特定问题,在一定程度上可能是可行的。 - nhahtdh
你能否在正则表达式中使用 | 时,识别匹配失败的部分? - Jindřich Mynarz
例如:([A-Z][0-9]{2}|[0-9]{2}[A-Z])和输入的090,你会报告哪个字符?第一个0还是最后一个0?匹配失败是因为它未能满足OR指定的所有情况,而导致失败的原因可能因情况而异。 - nhahtdh
是的,在模糊的情况下,仅仅识别第一个字符导致不匹配是行不通的。 - Jindřich Mynarz
2个回答

3

您需要将正则表达式模式分解为所有可能的部分匹配模式,并将这些模式从最长的匹配到最短的匹配(或没有匹配)进行排序。一旦找到匹配项,计算(部分)匹配的长度,您将得到导致不匹配的字符位置。从该位置开始,用一个字符的长度截取子字符串,就是导致不匹配的字符(如果有)。如果没有不匹配,则返回空(子)字符串。

var s = "123a45";
alert(s.substr(s.match(/^(\d{3}\s\d{2}|\d{3}\s\d|\d{3}\s|\d{0,3})/)[1].length,1));

http://jsfiddle.net/ETWWS/


1
介意添加一个简短的解释吗? - Octavian Helm
你认为这是一种通用解决方案,可以适用于所有类型的正则表达式吗?你认为你能自动生成包含所有部分匹配正则表达式的“扩展”正则表达式吗? - Jindřich Mynarz
1
@jindrichm - 每个固定长度的非替代模式都可以被分解。因此,以下示例无法进行分解:(1)\d{2,4}:\d{1,2},(2)(\w{3}\d{2}|\d{3}\w{2})等。 - Ωmega
是的,我看到大多数正则表达式不能这样处理。我认为最好按照@nhahtdh提出的方法编写自定义解析器。 - Jindřich Mynarz
1
@jindrichm - 是的,解析器是更安全的解决方案。我发布了我的正则表达式解决方案,因为你要求使用正则表达式... 但我必须更正自己 - 另一种模式可能会崩溃,因此问题是变量长度的子模式,所以如果您想使用正则表达式,则需要避免使用 {m,n}+*?。因此,例如,电话号码的正则表达式 \d{3}[-.]\d{3}[-.]\d{4} 是可以的,即使有可替代的分隔符破折号或句点/点号。好吧,你必须决定... 祝你好运!(Vela štestí a všecho dobré,Jindřichu!) - Ωmega

2
为了提供关于为什么输入无效的详细解释,最好编写一个小解析器并提供反馈。可以指出导致问题的字符,并给出更有帮助和有针对性的错误消息。
在解析器中,您可以使用正则表达式来断言字符串中的某些属性以生成有针对性的错误消息。例如,如果输入必须包含6个字符,并且前3个字符是数字,后3个字符是字母字符,则可以编写一个正则表达式来断言输入的长度以向用户报告错误。
要么这样,要么只使用您一直在使用的正则表达式并提供通用错误消息(附带有关如何正确输入的有用说明)。普通用户应该在最多2-3次尝试中能够正确输入数据。超过此数,可能是恶意用户,或要输入的数据不适用于所有用户,或者您的说明不足。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接