正则表达式获取测量值

regex to get measurements

我在文档中有这些测量结果

5.3 x 2.5 cm
11 x 11 mm
7 mm 
13 x 12 x 14 mm
13x12cm

我需要使用 python 使用正则表达式提取 5.3 x 2.5 厘米。

到目前为止我的代码在下面但是它不能正常工作

x = "\.\d{1,2}|\d{1,4}\.?\d{0,2}|\d{5}\.?\d?|\d{6}\.?"
by = "( )?(by|x)( )?"
cm = "(mm|cm|millimeter|centimeter|millimeters|centimeters)"
x_cm = "((" + x + " *(to|\-) *" + cm + ")" + "|(" + x + cm + "))"
xy_cm = "((" + x + cm + by + x + cm + ")" +"|(" + x + by + x + cm + ")" +"|(" + x + by + x + "))"
xyz_cm = "((" + x + cm + by + x + cm + by + x + cm + ")" + "|(" + x + by + x + by + x + cm + ")" + "|(" + x + by + x + by + x + "))"
m = "((" + xyz_cm + ")" + "|(" + xy_cm + ")" + "|(" + x_cm + "))"
a = re.compile(m)
print a.findall(text)

它给出的输出:

[('13', '13', '13', '13', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''), ('12', '12', '12', '12', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''), ('4', '4', '4', '4', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''), ('25', '25', '25', '25', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''),

使用 Regex,您应该始终慢慢地建立您的表达式以获得您想要的。例如

s = "5.3 x 2.5 cm"

您想在这里找到号码吗?

re.findall("\d+", s)

给你所有的整数:

["5", "3", "2", "5"]

好的,如果您的数字可以是浮点数但不一定是浮点数怎么办。然后你用一个非捕获匹配组扩展你的表达式,这个匹配组有一个点,后面可能还有一些数字。

re.findall("\d+(?:\.\d*)?", s)

这给了你

["5.3", "2.5"]

然后就可以取周围任意个空格的乘法:

re.findall("(\d+(?:\.\d*)?)\s*x\s*(\d+(?:\.\d*)?)", s)

现在将数字放在匹配组中会得到一个元组。

[("5.3", "2.5")]

然后您可以继续学习单位:

re.findall("(\d+(?:\.\d*)?)\s*x\s*(\d+(?:\.\d*)?)\s*(cm|mm)", s)

给你你想要的元组:

[("5.3", "2.5", "cm")]

等等。

如果您像这样构建您的正则表达式,您就有机会看到从一个更改到下一个更改有什么中断。像上面发布的那样调试一个巨大的正则表达式是一项不值得去做的任务。

我不会将我的单元正则表达式命名为 cm,这对于将来维护您的代码的任何人来说都是相当混乱的。除此之外,您需要对要允许的数字格式有一些明确的要求。也许有人会输入科学记数法等等。你的正则表达式会变得很复杂。

当前正则表达式的唯一问题是两个:

  • 你需要摆脱捕获组,因为 .findall 将提取所有捕获的子字符串而不是整个匹配值(但是,这并不重要,你不妨使用 re.finditer 和得到 match.group(0))
  • 主要问题是你没有对x模式进行分组,数字格式的交替破坏了最终模式的结构。

快速修复看起来像

x = "(?:\.\d{1,2}|\d{1,4}\.?\d{0,2}|\d{5}\.?\d?|\d{6}\.?)"
by = "(?: )?(?:by|x)(?: )?"
cm = "(?:mm|cm|millimeter|centimeter|millimeters|centimeters)"
x_cm = "(?:" + x + " *(?:to|\-) *" + cm + "|" + x + cm + ")"
xy_cm = "(?:" + x + cm + by + x + cm +"|" + x + by + x + cm +"|" + x + cm + by + x +"|" + x + by + x + ")"
xyz_cm = "(?:" + x + cm + by + x + cm + by + x + cm + "|" + x + by + x + by + x + cm + "|" + x + by + x + by + x + ")"
m = "{}|{}|{}".format(xyz_cm, xy_cm, x_cm) 

看到Python demo印刷

['5.3 x 2.5', '11 x 11', '13 x 12 x 14', '13x12cm']

为了进一步增强它,考虑 xbycm 的所有可能性,也许使用 str.format 而不是串联。