正则表达式进行测量

时间:2017-09-02 07:22:26

标签: python regex units-of-measurement

我在文件中有这些测量

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 cm。

到目前为止,我的代码在下面,但它无法正常工作

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', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''),

2 个答案:

答案 0 :(得分:4)

使用正则表达式,你应该总是慢慢建立你的表达式来获得你想要的东西。 E.g。

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,这对于将来维护代码的人来说非常困惑。除此之外,您需要对要允许的数字格式有一些明确的要求。也许有人会输入科学记数法等。你的正则表达式会变得非常复杂。

答案 1 :(得分:2)

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

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

快速修复将如下所示

x

请参阅Python demo打印

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) 

要进一步加强它,请考虑['5.3 x 2.5', '11 x 11', '13 x 12 x 14', '13x12cm'] xby的所有可能性,并使用cm而不是连接。