我一直在使用标准([0-9]+)
模式来匹配字符串中的数字,但现在有一个奇怪的边缘情况。我想匹配以下内容:
123
456
.123
123.
%123
31
14
2
100.55
555.10
在上述情况下,非数字字符是:
.
%
s
h
n
d
但他们可能是各种各样的角色。
想法?
JS 或 PHP 会很棒。
我一直在使用标准([0-9]+)
模式来匹配字符串中的数字,但现在有一个奇怪的边缘情况。我想匹配以下内容:
123
456
.123
123.
%123
31
14
2
100.55
555.10
在上述情况下,非数字字符是:
.
%
s
h
n
d
但他们可能是各种各样的角色。
想法?
JS 或 PHP 会很棒。
从一个能得到你想要的东西的模式开始:
\d+
现在您还想匹配十进制数字,因此扩展您的选项:
这个匹配数字后跟一个可选的小数点
\d+\.?
这个匹配十进制数字:
\d*\.\d+
加入两者将为您提供可靠的数字匹配模式(如果您不想匹配类似的数字,这可能仍然存在问题000.0000
):
(?:\d+\.?|\d*\.\d+)
现在是棘手的部分。您需要准确确定哪些其他字符可能是数字的前缀或后缀。
给定示例,我将做出以下假设:
%
可以前缀小数,但没有后缀st
, nd
, rd
, 并且th
只能作为整数后缀鉴于这些假设:
%
字符可以选择匹配小数:
(?:%?(?:\d+\.?|\d*\.\d+))
可以匹配带后缀的整数(这不验证后缀,1nd
将是有效的):
(?:\d+(?:st|nd|rd|th)
加入这两种模式会产生:
(?:(?:%?(?:\d+\.?|\d*\.\d+))|(?:\d+(?:st|nd|rd|th)))
当然,您可能希望将匹配限制为整个字符串:
/^(?:(?:%?(?:\d+\.?|\d*\.\d+))|(?:\d+(?:st|nd|rd|th)))$/
我试图为所有情况创建几个规则:
(\d+(?:\.\d*)?) // 123 ; 123. ; 123.45
([%.]\d+) // %123 ; .123
(\d+(?:st|nd|th)) // 31st ; 2nd ; 14th
然后混合:
((?:\d+(?:\.\d*)?)|(?:[%.]\d+)|(?:\d+(?:st|nd|th)))
如果您想要更短的内容,您可以简单地使用([%.\dshnd]+)
,但这会捕获许多不需要的条目,例如%%123%%
.
如果您正在寻找您期望的模式的验证(如日期?),您可以这样做:
[\d.%]*(nd|st|th){0,1}
如果你知道 % 的位置是领先的,或者你只有一个小数,或者如果你不想要 st/nd/etc 的小数,你可以这样细化:
([%]){0,1}[\d]*((((\.[\d]+){0,1}){0,1})|((nd|st|th|rd){0,1}))
我仍然没有在任何地方处理空间,但我认为您可以看到如何添加它?此外,您可能希望确保第 1 次与第 11 次等 - 如果您担心进一步改进验证可以开始进行类似日期的操作(您也许可以更好地使用谷歌搜索):
([023]){0,1}1st|([02]){0,1}2nd|([02]){0,1}3rd|(11|12|13|30|(([012]){0,1}(([4-9])|0))th)
那里有一些额外的括号,试图尽可能清楚
这一款适合您的需求:
^([.]|%)?\d+(((?<=^1)|(?<!^1)1)st|(?<!^1)((?<=^2)|2)nd|(?<!^1)((?<=^3)|3)rd|th|[.]\d*)?$
^ # start of the string
([.]|%)? # . or % {0 or 1 time}
\d+ # any digit {1 or more times}
(
((?<=^1)|(?<!^1)1)st # either (1) or (ending with 1 but not 11) followed by st
|(?<!^1)((?<=^2)|2)nd # either (2) or (ending with 2 but not 12) followed by nd
|(?<!^1)((?<=^3)|3)rd # either (3) or (ending with 3 but not 13) followed by rd
|th # th
|[.]\d* # . followed by (a digit {0 or more times})
)? # {0 or 1 time}
$ # end of the string
请注意,JS 将无法理解此正则表达式,因为它不支持后视(?<=
和?<!
)。