用正则expression式匹配数字 – 只有数字和逗号
我不知道如何构build示例值的正则expression式:
123,456,789 -12,34 1234 -8
你可以帮帮我吗?
如果你只想允许数字和逗号, ^[-,0-9]+$
是你的正则expression式。 如果您还想要空格,请使用^[-,0-9 ]+$
。
但是,如果你想允许正确的数字,最好去这样的事情:
^([-+] ?)?[0-9]+(,[0-9]+)?$
或简单地使用.net的数字parsing器 (对于各种NumberStyles,请参阅MSDN ):
try { double.Parse(yourString, NumberStyle.Number); } catch(FormatException ex) { /* Number is not in an accepted format */ }
什么是数字?
对于你的 “简单”问题,我有一个简单的问题:“一个数字”是什么意思?
-
−0
是一个数字? - 你觉得
√−1
怎么样? -
⅝
或⅝
是数字吗? - 一个号码是
186,282.42±0.02
英里/秒?还是两三个呢? - 是
6.02e23
一个数字? - 是
3.141_592_653_589
一个数字?π
或How怎么ℯ
? 和−2π⁻³ ͥ
? -
0.083̄
有多less个数字? -
128.0.0.1
有多less个数字? - 什么号码持有? 怎么
⚂⚃
? -
10,5 mm
有一个数字,还是有两个? -
∛8³
是一个数字 – 还是三个? -
ↀↀⅮⅭⅭⅬⅫ AUC
代表2762或2009年的数字是ↀↀⅮⅭⅭⅬⅫ AUC
? - 是
४५६७
和৭৮৯৮
号码? - 那么
0b111101101
和0b111101101
呢? - 是不是一个数字?
NaN
? -
④②
是一个数字吗? 那么⓰
? - 你觉
㊅
? -
ℵ₀
和ℵ₁
与数字有什么关系? 或ℝ
,ℚ
和ℂ
?
build议模式
另外,你是否熟悉这些模式? 你能解释每个人的利弊吗?
-
/\D/
-
/^\d+$/
-
/^\p{Nd}+$/
-
/^\pN+$/
-
/^\p{Numeric_Value:10}$/
-
/^\P{Numeric_Value:NaN}+$/
-
/^-?\d+$/
-
/^[+-]?\d+$/
-
/^-?\d+\.?\d*$/
-
/^-?(?:\d+(?:\.\d*)?|\.\d+)$/
-
/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/
-
/^((\d)(?(?=(\d))|$)(?(?{ord$3==1+ord$2})(?1)|$))$/
-
/^(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))$/
-
/^(?:(?:[0-9a-fA-F]{1,2}):(?:[0-9a-fA-F]{1,2}):(?:[0-9a-fA-F]{1,2}):(?:[0-9a-fA-F]{1,2}):(?:[0-9a-fA-F]{1,2}):(?:[0-9a-fA-F]{1,2}))$/
-
/^(?:(?:[+-]?)(?:[0123456789]+))$/
-
/(([+-]?)([0123456789]{1,3}(?:,?[0123456789]{3})*))/
-
/^(?:(?:[+-]?)(?:[0123456789]{1,3}(?:,?[0123456789]{3})*))$/
-
/^(?:(?i)(?:[+-]?)(?:(?=[0123456789]|[.])(?:[0123456789]*)(?:(?:[.])(?:[0123456789]{0,}))?)(?:(?:[E])(?:(?:[+-]?)(?:[0123456789]+))|))$/
-
/^(?:(?i)(?:[+-]?)(?:(?=[01]|[.])(?:[01]{1,3}(?:(?:[,])[01]{3})*)(?:(?:[.])(?:[01]{0,}))?)(?:(?:[E])(?:(?:[+-]?)(?:[01]+))|))$/
-
/^(?:(?i)(?:[+-]?)(?:(?=[0123456789ABCDEF]|[.])(?:[0123456789ABCDEF]{1,3}(?:(?:[,])[0123456789ABCDEF]{3})*)(?:(?:[.])(?:[0123456789ABCDEF]{0,}))?)(?:(?:[G])(?:(?:[+-]?)(?:[0123456789ABCDEF]+))|))$/
-
/((?i)([+-]?)((?=[0123456789]|[.])([0123456789]{1,3}(?:(?:[_,]?)[0123456789]{3})*)(?:([.])([0123456789]{0,}))?)(?:([E])(([+-]?)([0123456789]+))|))/
我怀疑上面的一些模式可能会满足您的需求。 但是我不能告诉你哪一个或那个,或者如果没有,就提供给你另一个 – 因为你没有说出“number”是什么意思。
正如你所看到的,有很多数字的可能性:事实上,这个数字可能大概是1/1。 ☺
build议模式的关键
下面列出的每个编号说明都描述了上面列出的相应编号模式的模式。
- 匹配string中是否有任何非数字 ,包括换行符等空格。
- 只有当string只包含数字时才匹配,可能除了尾部换行符。 请注意,数字被定义为具有属性常规类别十进制数字,该数字可用为
\p{Nd}
,\p{Decimal_Number}
或\p{General_Category=Decimal_Number}
。 这实际上只是数字types类别为十进制的那些代码点的反映,它可以用作\p{Numeric_Type=Decimal}
。 - 这与大多数正则expression式语言中的2相同。 Java在这里是一个例外,因为它不会像
\w
和\W
,\d
和\D
,\s
和\S
和\b
或\B
这样简单的charclass转义映射到适当的Unicode属性中。 这意味着您不得在Java中使用任何八位单字符转义符,因为即使Java在内部始终使用Unicode字符,它们也只能用于ASCII。 - 这与3略有不同,因为它不限于小数,而可以是任何数字; 也就是任何带有
\pN
,\p{Number}
或\p{General_Category=Number}
属性的\p{General_Category=Number}
。 这些包括\p{Nl}
或\p{Letter_Number}
用于罗马数字和\p{No}
或\p{Other_Number}
等下标和下标数字,分数和圈数。 - 这只匹配那些完全由十进制数字组成的string,比如
Ⅹ
罗马数字十,⑩
,⑽
,⒑
,❿
,❿
,➉
和➓
。 - 只有那些包含缺less数字值NaN的字符的string; 换句话说,所有的字符必须有一些数字值。
- 只匹配十进制数字,可select带领先的HYPHEN MINUS。
- 与7相同,但现在如果符号是正数而不是负数,也可以使用。
- 查找十进制数字,可选的HYPHEN MINUS和可选的FULL STOP加上零或更多的十进制数字。
- 与9相同,但在点之前不需要数字。
- 每个C和许多其他语言的标准浮点标记,允许使用科学记数法。
- 查找任意脚本的两位或更多小数的数字,按照降序排列,如987或54321.这个recursion正则expression式包含一个Perl代码调用,用于检查向前看的数字是否具有当前数字的后继代码点值; 也就是说,它的序数值更大一些。 人们可以在PCRE中使用C函数作为标注。
- 这将在有效范围内查找具有四个十进制数字的有效IPv4地址,如128.0.0.1或255.255.255.240,但不是999.999.999.999。
- 这寻找一个有效的MAC地址,所以六个冒号分开的两个ASCIIhex数字对。
- 这在整个ASCII范围内寻找可选的前导符号。 这是匹配ASCII整数的正常模式。
- 这就像15,除了需要一个逗号来分隔三个组。
- 这就像15,除了逗号分隔组现在是可选的。
- 这是在ASCII中匹配C样式浮点数的正常模式。
- 这就像18,但需要一个逗号分隔3组,而不是以10为底。
- 这就像19,但在hex。 请注意,可选的指数现在由G代替E来表示,因为E是有效的hex数字。
- 这将检查该string是否包含一个C风格的浮点数字,但是在它们之间用逗号或下划线(LOW LINE)的每三位数字组成一个可选的分组分隔符。 它还将该string存储到
\1
捕获组中,在匹配成功后以$1
提供。
来源和可维护性
模式编号1,2,7-11来自问题“我如何validationinput?”中Perl 常见问题列表的前一个版本。 该部分已被build议使用由Abigail和Damian Conway编写的Regexp :: Common模块。 原始模式仍然可以在Perl Cookbook的 Recipe 2.1中find,“检查一个string是否是有效的数字”,可以find令人眼花缭乱的多种语言的解决scheme,包括ada,common lisp,groovy,guile, haskell,java,merd,ocaml,php,pike,python,rexx,ruby和tcl在PLEAC项目中的使用 。
模式12可以更明确地重写
m{ ^ ( ( \d ) (?(?= ( \d ) ) | $ ) (?(?{ ord $3 == 1 + ord $2 }) (?1) | $ ) ) $ }x
它使用regexrecursion ,在许多模式引擎中都可以find它,包括Perl和所有PCRE派生语言。 但它也使用embedded式代码标注作为其第二个条件模式的testing; 据我所知,代码标注仅在Perl和PCRE中可用。
模式13-21从前面提到的Regexp :: Common模块中得到。 请注意,为了简洁起见,这些代码都是没有空格和注释的,你在生产代码中肯定会想要的。 下面是在/x
模式下看起来如何:
$real_rx = qr{ ( # start $1 to hold entire pattern ( [+-]? ) # optional leading sign, captured into $2 ( # start $3 (?= # look ahead for what next char *will* be [0123456789] # EITHER: an ASCII digit | [.] # OR ELSE: a dot ) # end look ahead ( # start $4 [0123456789]{1,3} # 1-3 ASCII digits to start the number (?: # then optionally followed by (?: [_,]? ) # an optional grouping separator of comma or underscore [0123456789]{3} # followed by exactly three ASCII digits ) * # repeated any number of times ) # end $4 (?: # begin optional cluster ( [.] ) # required literal dot in $5 ( [0123456789]{0,} ) # then optional ASCII digits in $6 ) ? # end optional cluster ) # end $3 (?: # begin cluster group ( [E] ) # base-10 exponent into $7 ( # exponent number into $8 ( [+-] ? ) # optional sign for exponent into $9 ( [0123456789] + ) # one or more ASCII digits into $10 ) # end $8 | # or else nothing at all ) # end cluster group ) }xi; # end $1 and whole pattern, enabling /x and /i modes
从软件工程angular度来看,在上面的/x
模式版本中使用的样式仍然有几个问题。 首先,有大量的代码重复,你看到相同的[0123456789]
; 如果其中一个序列意外地遗漏了数字,会发生什么? 其次,你依靠位置参数,你必须数。 这意味着你可能会写如下的东西:
( $real_number, # $1 $real_number_sign, # $2 $pre_exponent_part, # $3 $pre_decimal_point, # $4 $decimal_point, # $5 $post_decimal_point, # $6 $exponent_indicator, # $7 $exponent_number, # $8 $exponent_sign, # $9 $exponent_digits, # $10 ) = ($string =~ /$real_rx/);
这是坦率的可恶! 很容易弄错编号,很难记住哪些符号名字在哪里,而且很难写,特别是如果你不需要所有这些部分。 重写,以使用命名的组,而不是只是编号的。 再一次,我将使用Perl语法作为variables,但模式的内容应该可以在任何支持指定组的地方工作。
use 5.010; # Perl got named patterns in 5.10 $real_rx = qr{ (?<real_number> # optional leading sign (?<real_number_sign> [+-]? ) (?<pre_exponent_part> (?= # look ahead for what next char *will* be [0123456789] # EITHER: an ASCII digit | [.] # OR ELSE: a dot ) # end look ahead (?<pre_decimal_point> [0123456789]{1,3} # 1-3 ASCII digits to start the number (?: # then optionally followed by (?: [_,]? ) # an optional grouping separator of comma or underscore [0123456789]{3} # followed by exactly three ASCII digits ) * # repeated any number of times ) # end <pre_decimal_part> (?: # begin optional anon cluster (?<decimal_point> [.] ) # required literal dot (?<post_decimal_point> [0123456789]{0,} ) ) ? # end optional anon cluster ) # end <pre_exponent_part> # begin anon cluster group: (?: (?<exponent_indicator> [E] ) # base-10 exponent (?<exponent_number> # exponent number (?<exponent_sign> [+-] ? ) (?<exponent_digits> [0123456789] + ) ) # end <exponent_number> | # or else nothing at all ) # end anon cluster group ) # end <real_number> }xi;
现在抽象被命名,这有助于。 你可以通过名字把这些小组拉出来,而你只需要那些你关心的小组。 例如:
if ($string =~ /$real_rx/) { ($pre_exponent, $exponent_number) = @+{ qw< pre_exponent exponent_number > }; }
还有一件事要做到这一点,使其更容易维护。 问题是还有太多的重复,这意味着在一个地方太容易改变,而另一个地方却不太容易改变。 如果你正在做McCabe分析,你会说它的复杂性度量太高。 我们大多数人会说这是太过于缩进。 这使得难以遵循。 为了解决所有这些问题,我们需要的是一个“语法模式”,一个带有一个定义块来创build命名抽象,然后在稍后的比赛中,我们就像一个子例程调用。
use 5.010; # Perl first got regex subs in v5.10 $real__rx = qr{ ^ # anchor to front (?&real_number) # call &real_number regex sub $ # either at end or before final newline ################################################## # the rest is definition only; think of ## # each named buffer as declaring a subroutine ## # by that name ## ################################################## (?(DEFINE) (?<real_number> (?&mantissa) (?&abscissa) ? ) (?<abscissa> (?&exponent_indicator) (?&exponent) ) (?<exponent> (&?sign) ? (?&a_digit) + ) (?<mantissa> # expecting either of these.... (?= (?&a_digit) | (?&point) ) (?&a_digit) {1,3} (?: (?&digit_separator) ? (?&a_digit) {3} ) * (?: (?&point) (?&a_digit) * ) ? ) (?<point> [.] ) (?<sign> [+-] ) (?<digit_separator> [_,] ) (?<exponent_indicator> [Ee] ) (?<a_digit> [0-9] ) ) # end DEFINE block }x;
看看语法模式比原来的线条模式有多疯狂吗? 获得正确的语法也容易得多:我input了,甚至没有一个正则expression式需要纠正的语法错误。 (好的,我input了所有其他的语法错误,但是我一直在这样做一段时间:)
语法模式看起来更像一个BNF,而不像人们讨厌的丑陋的旧正则expression式。 他们阅读,写作和维护要容易得多。 那么让我们没有更丑陋的模式,好吗?
尝试这个:
^-?\d{1,3}(,\d{3})*(\.\d\d)?$|^\.\d\d$
允许:
1 12 .99 12.34 -18.34 12,345.67 999,999,999,999,999.99
由于这个问题在四年后重新开放,我想提出一个不同的看法。 由于有人花了很多时间处理正则expression式,我的观点是这样的:
答:如果可能的话,不要使用正则expression式来validation数字
如果可能的话,使用你的语言。 可能有些函数可以帮助您确定string中包含的值是否是有效的数字。 这就是说,如果你接受各种格式(逗号等),你可能没有select。
B.不要手动编写正则expression式来validation数字范围
- 写一个正则expression式来匹配给定范围内的数字是很困难的。 即使写一个正则expression式来匹配1到10之间的数字,你也可能犯了一个错误。
- 一旦你有一个数字范围的正则expression式,很难debugging。 首先,看看是很糟糕的。 其次,你怎么能确定它匹配你想要的所有值,而不匹配任何你不想要的值? 坦率地说,如果你是独自一人,没有同伴看你的肩膀,你不能。 最好的debugging技术是以编程方式输出一系列数字,并根据正则expression式进行检查。
- 幸运的是,有一些工具可以自动生成一个数字范围的正则expression式。
C.明智地消耗正则expression能量:使用工具
- 匹配给定范围内的数字是一个已经解决的问题。 没有必要尝试重新发明轮子。 这是一个可以通过一个程序机械地解决的问题,保证没有错误。 利用这个免费的旅程。
- 解决一个数字范围的正则expression式可能会有趣的几次学习的目的。 除此之外,如果你有精力投资于提高你的正则expression式技能,把它花在一些有用的东西上,比如加深你对正则expression式的理解,阅读Unicode正则expression式 ,使用零宽度匹配或者recursion,阅读SO正则expression式常见问题并发现整洁的技巧,如如何从正则expression式匹配排除某些模式 …或阅读经典,如Matering正则expression式,第三版或正则expression式食谱,第二版 。
对于工具,您可以使用:
- 在线: Regex_for_range
- 离线:我知道的唯一一个是正则expression式大师Jan Goyvaerts的
RegexMagic
(不是免费的)。 这是他的初学者正则expression式产品,我记得它有一个范围广泛的select,在给定的范围内产生数字,除其他function。 - 如果条件过于复杂,则自动生成两个范围…然后用交替操作符
|
将它们连接起来
D.练习:为问题中的规范build立一个正则expression式
这些规格是相当广泛的…但不一定含糊不清。 我们再看一下示例值:
123,456,789 -12,34 1234 -8
前两个值如何关联? 首先,逗号与三个权力组相匹配。 在第二种情况下,它可能与欧式风格的数字格式中的小数点匹配。 这并不意味着我们应该在任何地方都允许数字,就像1,2,3,44
。 同样道理,我们不应该是限制性的。 例如,接受的答案中的正则expression式将不符合123,456,789
中的一个要求(请参阅演示 )。
我们如何build立我们的正则expression式来匹配规格?
- 让我们锚定
^
和$
之间的expression式来避免子匹配 - 让我们允许一个可选的减号:
-?
- 让我们在交替的两边匹配两种types的数字
(?:this|that)
: - 左边是一个欧式数字,可选用逗号分隔小数部分:
[1-9][0-9]*(?:,[0-9]+)?
- 在右边,有数千个分隔符:
[1-9][0-9]{1,2}(?:,[0-9]{3})+
完整的正则expression式:
^-?(?:[1-9][0-9]*(?:,[0-9]+)?|[1-9][0-9]{1,2}(?:,[0-9]{3})+)$
看演示 。
这个正则expression式不允许从0
开始的欧式风格的数字,比如0,12
。 这是一个function,而不是一个错误。 为了匹配这些,一个小的调整将做到:
^-?(?:(?:0|[1-9][0-9]*)(?:,[0-9]+)?|[1-9][0-9]{1,2}(?:,[0-9]{3})+)$
看演示 。
尝试这个:
^-?[\d\,]+$
它将允许一个可选的-
作为第一个字符,然后是逗号和数字的任意组合。
^-? # start of line, optional - (\d+ # any number of digits |(\d{1,3}(,\d{3})*)) # or digits followed by , and three digits ((,|\.)\d+)? # optional comma or period decimal point and more digits $ # end of line
^[-+]?(\d{1,3})(,?(?1))*$
Debuggex演示
那么它是什么?!
-
^
标记string的开头 -
[-+]?
在string开始之后允许减号或加号 -
(\d{1,3})
在一行中匹配至less一个和最多三个({1,3}
)数字(\d
– 通常为[0-9]
)并对它们进行分组(括号(...)
该组)作为第一组 -
(,?(?1))*
好吧,我们来分解一下-
(...)
build立另一个组( 不是那么重要 ) -
,?
匹配一个逗号(如果存在)在第一个数字序列之后 -
(?1)
再次匹配第一组的模式(记住(\d{1,3})
); 换句话说:在这一点上,expression式匹配一个符号(加号/减号/无),后跟一串数字,后面可能跟着一个逗号,接着是另一个数字序列。 -
(,?(?1))*
,*
重复第二部分(逗号&序列)尽可能经常
-
-
$
最后匹配string的结尾
这种expression的优点是,为了避免在你的expression中一遍又一遍地定义相同的模式…呃,有时候缺点是复杂性: – /
在Java中,您可以使用java.util.Scanner
及其useLocale
方法
Scanner myScanner = new Scanner(input).useLocale( myLocale) isADouble = myScanner.hasNextDouble()
例如:
^(-)?([,0-9])+$
它应该工作。 用你想要的任何语言来实现它。
尝试这个:
boxValue = boxValue.replace(/[^0-9\.\,]/g, "");
此RegEx仅匹配数字,点和逗号。