我正在尝试匹配整数或十进制数,后跟两个点..
,后跟另一个整数或十进制数。在点的每一侧,数字是可选的,但它们必须出现在一侧或另一侧。我将使用Java进行实际实现(String#matches()
)。
例如,这些应匹配:
..12
12..
12..24
12.23..14.25
虽然这些不应该:
..
foo
foo..bar
bazz12..12buzz
foo11..22
11..22efg
这是我能够提出的最好的:
(^(\d+\.?\d+)\.\.(\d+\.?\d+)?$)|(^(\d+\.?\d+)?\.\.(\d+\.?\d+)$)
我觉得它可能会更好。我错了吗?请注意,我有两个与中间管道几乎相同的子句,唯一的区别是一个匹配..12
而另一个匹配12..
编辑: 感谢所有的投入!我选了@anubhava,因为我要求最短的。还要感谢我指出原始表达中的错误!
答案 0 :(得分:4)
您可以使用前瞻来缩短正则表达式:
^(?=\.*\d)(?:\d+(?:\.\d+)?)?\.\.(?:\d+(?:\.\d+)?)?$
Java正则表达式:
Pattern p =
Pattern.compile("^(?=\\.*\\d)(?:\\d+(?:\\.\\d+)?)?\\.\\.(?:\\d+(?:\\.\\d+)?)?$");
(?=\.*\d)
是确保至少有一位数字的正向前瞻,从而确保我们不仅仅将..
与有效输入相匹配。
答案 1 :(得分:2)
你可以使用这种模式,这种模式不是最短但更有效率的,没有无用的东西:
\d
注意:
默认情况下,[0-9]
有时可以匹配所有unicode数字。更准确地说,您可以用matches()
替换所有这些以获得更快的结果(更少的字符来测试)。
如果你使用\d+(?:\.\d+)?\.\.(?:\d+(?:\.\d+)?)?|\.\.\d+(?:\.\d+)?
方法(在这种情况下似乎是合乎逻辑的),模式是隐式锚定的,所以你可以写:
^(\d+(\.\d+)?)?\.\.(?(1)(?1)?|(?1))$
如果你想要最短的模式你可以写(perl,pcre,ruby,但不是Java!):
def apply_filter(x):
filterer = {
1: 'ether proto 0x88B8',
2: 'tcp port 102',
3: 'ether proto 0x88BA'
}
return filterer.get(x, '')
import unittest
from new_format import apply_filter
class test_apply_filter(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_filter_by_name(self):
self.assertEqual(apply_filter(1),"ether proto 0x88B8")
self.assertEqual(apply_filter(2),"tcp port 102")
self.assertEqual(apply_filter(3),"ether proto 0x88BA")
if __name__ == '__main__':
unittest.main()
它很短但效率低。
答案 2 :(得分:2)
\d
取代[0-9]
。以下是一些统计数据:
Author: OP, Len: 63, Memory: 784, Time: 0.9156907489523292
Author: Casimir, Len: 59, Memory: 544, Time: 0.7456484709400684
Author: Casimir0-9, Len: 77, Memory: 568, Time: 0.7377533189719543
Author: anubhava, Len: 51, Memory: 472, Time: 0.8746482610004023
编辑:根据评论中的建议更新了“1..2”测试用例,也包括超长情况。
Author: Anony-Mousse, Len: 45, Memory: 456, Time: 1.3653777639847249
Author: Casimir, Len: 59, Memory: 544, Time: 1.1941137500107288
Author: anubhava, Len: 51, Memory: 472, Time: 1.5450064099859446
Author: OP, Len: 63, Memory: 784, Time: 1.82177433592733
Failed: should match '1..2'
Author: Casimir0-9, Len: 77, Memory: 568, Time: 1.1341593150282279
以下是我测试的方式:
import re
import sys
from timeit import timeit
Compiled_re = None
Failures = None
Should_match = (
"1..2", # EDIT: Updated per comments
"..12",
"12..",
"12..24",
"12.23..14.25",
"123.456789012345..98765.43210",
)
Shouldnt_match = (
"..",
"foo",
"foo..bar",
"bazz12..12buzz",
"foo11..22",
"11..22efg",
"123.456789012345..98765.43210.",
)
def test_re():
cre = Compiled_re
global Failures
Failures = {}
for test in Should_match:
if cre.match(test) is not None:
pass
else:
Failures[test] = "Failed: should match '{:s}'".format(test)
for test in Shouldnt_match:
if cre.match(test) is None:
pass
else:
Failures[test] = "Failed: should not match '{:s}'".format(test)
candidates = {
r"(^(\d+\.?\d+)\.\.(\d+\.?\d+)?$)|(^(\d+\.?\d+)?\.\.(\d+\.?\d+)$)":"OP",
r"^(?:\d+(?:\.\d+)?\.\.(?:\d+(?:\.\d+)?)?|\.\.\d+(?:\.\d+)?)$":"Casimir",
#r"^(\d+(?:\.\d+)?)?\.\.(\d+(?:\.\d+)?)?$":"dasblinkenlight",
r"^(?=\.*\d)(?:\d+(?:\.\d+)?)?\.\.(?:\d+(?:\.\d+)?)?$":"anubhava",
r"^(?:[0-9]+(?:\.[0-9]+)?\.\.(?:[0-9]+(?:\.[0-9]+)?)?|\.\.[0-9]+(?:\.[0-9]+)?)$":"Casimir0-9",
r"^(?:\d+\.)?\d*(?:\d\.\.|\.\.\d)(?:\d+\.)?\d*$":"Anony-Mousse",
}
for pattern,author in candidates.items():
Compiled_re = re.compile(pattern)
length = len(pattern)
mem = sys.getsizeof(Compiled_re)
time = timeit('test_re()', setup='from __main__ import test_re',number=100000)
print("Author: {author}, Len: {length}, Memory: {mem}, Time: {time}".format(
author=author, length=length, mem=mem, time=time))
if Failures:
for test in Should_match + Shouldnt_match:
if test in Failures:
print(Failures[test])
答案 3 :(得分:2)
保持替代品的效率不高。
^(?:\d+\.)?\d*(?:\d\.\.|\.\.\d)(?:\d+\.)?\d*$
应该做的伎俩,而不是引起太多的回溯。
但是,我认为滥用正则数据解析数字是个好主意。他们不是为了这个。例如,这可能是您的模式的有效输入:
1.2345678901234567890..
但它超过了双精度。还有科学记数法:1e-10..1e10
而不是0.000000001..10000000000
。您仍然不知道左侧是否小于右侧。
我建议你坚持这样做1.在..
拆分,2。使用经过充分测试的双解析器解析两边,3。检查其他约束,例如至少一方被设置,例如如果两者都设置,则左< =右。
答案 4 :(得分:1)
如果您首先使用前瞻以确保字符串不仅仅是..
,那么您可以将这两个数字设为可选并避免更改:
^(?!\.\.$)(\d+(\.\d+)?)?\.\.(\d+(\.\d+)?)?$
顺便说一句,(\d+\.?\d+)
要求至少有两位数字,即使没有小数点也是如此。也许在你的情况下没问题,但这种方式也更有效率。
通常,您希望避免使正则表达式的相邻部分与字符串的相同部分匹配。如果无法匹配,则正则表达式引擎将花费大量时间尝试将某些数字与第一个\d+
匹配,而某些数字与第二个\d+
匹配,以及每种可能的组合。