use*_*618 52 .net regex numbers matching
我无法弄清楚如何为示例值构造一个正则表达式:
123,456,789
-12,34
1234
-8
Run Code Online (Sandbox Code Playgroud)
你可以帮帮我吗?
tch*_*ist 475
对于你的 "简单"问题我有一个简单的问题:你用"数字"究竟是什么意思?
?0
一个数字???1
得怎么样??
或?
数字?186,282.42±0.02
英里/秒的一个数字 - 还是两个或三个?6.02e23
一个数字?3.141_592_653_589
一个数字?怎么样?
,或者?
?而且?2??³ ?
?0.083?
?128.0.0.1
??
拿着什么号码?怎么样??
?10,5 mm
有一个数字 - 或者它有两个??8³
一个数字 - 或者它是三个? ??????? AUC
代表什么号码,2762或2009?????
和????
数字?0377
,0xDEADBEEF
和0b111101101
?Inf
一个数字?是NaN
吗???
一个数字?怎么样?
??
得怎么样???
,并??
与数字呢?或者?
,?
和?
?另外,你熟悉这些模式吗?你能解释一下每个人的利弊吗?
/\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]+))|))/
我怀疑上面的一些模式可能满足您的需求.但是我不能告诉你哪一个 - 或者,如果没有一个,那么为你提供另一个 - 因为你没有用"数字"说出你的意思.
正如你看到的,有数量庞大的数量可能:大抵相当ℵ₁值得他们,其实.☺
下面列出的每个编号说明描述了上面列出的相应编号图案的图案.
\p{Nd}
,\p{Decimal_Number}
或\p{General_Category=Decimal_Number}
.转向实际上只是那些数字类型为十进制的代码点的反映,可用作\p{Numeric_Type=Decimal}
.\w
和\W
,\d
和\D
,\s
和\S
,\b
或者映射\B
到相应的Unicode属性中.这意味着你不能对Java中的任何Unicode数据使用这八个单字符转义中的任何一个,因为它们仅适用于ASCII,即使Java内部始终使用Unicode字符.\pN
,\p{Number}
或\p{General_Category=Number}
财产.这些包括\p{Nl}
或\p{Letter_Number}
用于罗马数字和/ \p{No}
或\p{Other_Number}
下标和下标数字,分数和带圆圈的数字之类的东西,其中包括计数杆等.?
罗马数字十位,并且?
,?
,?
,?
,?
,?
,和?
.\1
捕获组中,$1
在匹配成功后可用.模式编号1,2,7-11来自问题"如何验证输入?" 中的Perl 常见问题列表的先前版本.该部分已被使用由Abigail和Damian Conway编写的Regexp :: Common模块的建议所取代.原始模式仍然可以在Perl Cookbook的 Recipe 2.1中找到,"检查字符串是否为有效数字",可以找到令人眼花缭乱的多种语言的解决方案,包括ada,common lisp,groovy,guile,在PLEAC项目中,haskell,java,merd,ocaml,php,pike,python,rexx,ruby和tcl .
模式12可以更清晰地重写
m{
^
(
( \d )
(?(?= ( \d ) ) | $ )
(?(?{ ord $3 == 1 + ord $2 }) (?1) | $ )
)
$
}x
Run Code Online (Sandbox Code Playgroud)
它使用正则表达式递归,它可以在许多模式引擎中找到,包括Perl和所有PCRE派生的语言.但它也使用嵌入式代码标注作为其第二个条件模式的测试; 据我所知,代码标注仅在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
Run Code Online (Sandbox Code Playgroud)
从软件工程的角度来看,/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/);
Run Code Online (Sandbox Code Playgroud)
这是坦率的可恶!很容易让编号错误,很难记住哪些符号名称在哪里,写起来很乏味,特别是如果你不需要所有这些.重写使用命名组而不是编号的组.同样,我将对变量使用Perl语法,但Pattern的内容应该适用于支持命名组的任何位置.
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;
Run Code Online (Sandbox Code Playgroud)
现在抽象被命名,这有所帮助.你可以按名称拉出组,你只需要你关心的组.例如:
if ($string =~ /$real_rx/) {
($pre_exponent, $exponent_number) =
@+{ qw< pre_exponent exponent_number > };
}
Run Code Online (Sandbox Code Playgroud)
还有一件事要做这个模式,以使其更易于维护.问题是仍然有太多的重复,这意味着它很容易在一个地方改变而在另一个地方不容易改变.如果您正在进行McCabe分析,您会说它的复杂度指标太高了.我们大多数人只会说它太缩进了.这使得很难遵循.为了解决所有这些问题,我们需要的是一个"语法模式",一个用于创建命名抽象的定义块,然后我们将其视为稍后在匹配中的子例程调用.
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;
Run Code Online (Sandbox Code Playgroud)
看看语法模式比原始的线条噪声模式更好吗?获得正确的语法也要容易得多:我输入的内容甚至没有需要纠正的一个正则表达式语法错误.(好吧,我输入了所有其他的没有任何语法错误,但我已经这样做了一段时间.:)
语法模式看起来更像是BNF而不是人们讨厌的丑陋的旧正则表达式.它们更容易阅读,编写和维护.所以,让我们没有更难看的模式,好吗?
Thi*_*ter 38
如果你只想允许数字和逗号,那么^[-,0-9]+$
你的正则表达式是什么.如果您还想允许空格,请使用^[-,0-9 ]+$
.
但是,如果你想允许正确的数字,最好使用这样的东西:
^([-+] ?)?[0-9]+(,[0-9]+)?$
Run Code Online (Sandbox Code Playgroud)
或者只是使用.net的数字解析器(对于各种NumberStyles,请参阅MSDN):
try {
double.Parse(yourString, NumberStyle.Number);
}
catch(FormatException ex) {
/* Number is not in an accepted format */
}
Run Code Online (Sandbox Code Playgroud)
试试这个:
^-?\d{1,3}(,\d{3})*(\.\d\d)?$|^\.\d\d$
Run Code Online (Sandbox Code Playgroud)
允许:
1
12
.99
12.34
-18.34
12,345.67
999,999,999,999,999.99
Run Code Online (Sandbox Code Playgroud)
由于这个问题在四年后重新开放,我想提出一个不同的看法.由于有人花了很多时间使用正则表达式,我的观点是这样的:
A.如果可能,请勿使用正则表达式验证数字
如果可能的话,请使用您的语言.可能有一些函数可帮助您确定字符串包含的值是否为有效数字.话虽这么说,如果你接受各种格式(逗号等),你可能没有选择.
B.不要手动编写正则表达式以验证数字范围
C.明智地花费你的正则表达能源:使用工具
对于工具,您可以使用:
RegexMagic
正则表达的大师Jan Goyvaerts(不是免费的).这是他的初学者正则表达式产品,我记得它有很多选项可以在给定范围内生成数字,以及其他功能.|
D.练习:为问题中的规范构建正则表达式
这些规格相当广泛......但不一定含糊不清.让我们再看一下样本值:
123,456,789
-12,34
1234
-8
Run Code Online (Sandbox Code Playgroud)
前两个值如何相关?在第一个中,逗号匹配三个权力组.在第二种情况下,它可能与欧洲大陆式数字格式的小数点相匹配.这并不意味着我们应该在任何地方允许数字,如1,2,3,44
.出于同样的原因,我们不应该是限制性的.例如,接受的答案中的正则表达式将不符合其中一个要求123,456,789
(参见演示).
我们如何构建我们的正则表达式以符合规范?
^
并$
避免子匹配-?
(?:this|that)
:[1-9][0-9]*(?:,[0-9]+)?
[1-9][0-9]{1,2}(?:,[0-9]{3})+
完整的正则表达式:
^-?(?:[1-9][0-9]*(?:,[0-9]+)?|[1-9][0-9]{1,2}(?:,[0-9]{3})+)$
Run Code Online (Sandbox Code Playgroud)
见演示.
这个正则表达式不允许以欧洲风格的数字开头0
,例如0,12
.这是一个功能,而不是一个bug.为了匹配这些,一个小的调整将做:
^-?(?:(?:0|[1-9][0-9]*)(?:,[0-9]+)?|[1-9][0-9]{1,2}(?:,[0-9]{3})+)$
Run Code Online (Sandbox Code Playgroud)
见演示.