如何设计一个可以安全捕获各种类型数字的正则表达式?
How to design a regular expression that can safely capture various types of numbers?
在我正在处理的文本语料库中,需要捕获各种类型的数字。具体来说,号码类型包括:
- 10000
- 10,000
- -3.33 × 10-3
- 8.×104(这实际上是8.×10**4,8.和×之间没有空格)
- 5×104(这实际上是5×10**4)
- 12.123
- 12
如何构造一个可以安全捕获所有七种类型数字的正则表达式?我从捕获浮点数的正则表达式[+-]?(?:[0-9]*\.?)[0-9]+
开始,想出了一个解决方案[+-]?(?:[0-9]*[\.\,\s\×])?\s?[0-9]+\-?[0-9]?
。但是,这不能涵盖所有的七种可能性,而且如果我只是对此进行更多修改,最终的解决方案似乎会很乏味。
有没有优雅的解决方案?
更新
根据 EatenbyaGuru 的建议,我想出了三个正则表达式来涵盖七种可能性
digit_part0 = r"[+-]?[0-9]*\.[0-9]+\s?(?:×\s?10-?[0-9])?"
digit_part1 = r"[+-]?[1-9][0-9]*\s?(?:×\s?10-?[0-9])?"
digit_part2 = r"[+-]?[1-9][0-9]*[\s,][0-9]+(?:\.[0-9]*)?"
其中 digit_prat0
用于涵盖案例 #3、4 和 6; digit_part1
用于涵盖案例 #5 和案例 7; digit_part2
用于覆盖情况 #1、2。此时,digit_part0
和 digit_part1
之间可能存在重叠情况。
更新 2
现在我构建了一个正则表达式,有望捕获所有可能性
[+-]?(?:[1-9][0-9]+[\s,])?(?:[0-9]+\.)?[0-9]+\s?(?:×\s?10-?[0-9])?
没有安全的通用方法来执行此操作。您只能根据输入数据开展工作并涵盖其中的案例,这始终意味着您需要适应并做出妥协。
以下正则表达式针对样本中定义的数字:
-?\d[\d .,]*\b
并像这样匹配:
- 10 000 (→
10 000
)
- 10,000 (→
10,000
)
- -3.33 × 10-3 (→
-3.33
, 10
, -3
)
- 8.×104(→
8
,104
)
- 5×104 (→
5
, 104
)
- 12.123 (→
12.123
)
- 12 (→
12
)
如果你想匹配表达式,你可以说X(?:YX)*
,其中X
是数字的正则表达式,Y
允许的运算符的正则表达式,包括周围的绒毛(例如空格)。
因此,如果我们说现在允许的运算符应该是 \.? *(?:×|-) *
(\.
只是为了涵盖您的 8.× 104
情况),您最终会得到:
-?\d[\d .,]*\b(?:\.? *(?:×|-) *-?\d[\d .,]*\b)*
│ | | || |
└─────X──────┘(?:└─────Y──────┘└─────X──────┘)*
匹配如下:
- 10 000 (→
10 000
)
- 10,000 (→
10,000
)
- -3.33 × 10-3 (→
-3.33 × 10-3
)
- 8.×104(→
8.× 104
)
- 5×104 (→
5×104
)
- 12.123 (→
12.123
)
- 12 (→
12
)
我相信您会发现这不够具体或不够通用的情况。根据需要更新“数字”和“运算符”组件。
例如,-?\d[\d .,]*\b
可能过于简单。没有什么可以阻止它匹配 1,,,,,0
或 10000.0,0.0,0
之类的东西。如果这样的事情不会出现在您的输入数据中,那么它可能没问题。如果您需要使其更智能以便识别合法数字分组或丢弃无意义的分隔符组合,请使其更智能。这一切都取决于。
在我正在处理的文本语料库中,需要捕获各种类型的数字。具体来说,号码类型包括:
- 10000
- 10,000
- -3.33 × 10-3
- 8.×104(这实际上是8.×10**4,8.和×之间没有空格)
- 5×104(这实际上是5×10**4)
- 12.123
- 12
如何构造一个可以安全捕获所有七种类型数字的正则表达式?我从捕获浮点数的正则表达式[+-]?(?:[0-9]*\.?)[0-9]+
开始,想出了一个解决方案[+-]?(?:[0-9]*[\.\,\s\×])?\s?[0-9]+\-?[0-9]?
。但是,这不能涵盖所有的七种可能性,而且如果我只是对此进行更多修改,最终的解决方案似乎会很乏味。
有没有优雅的解决方案?
更新
根据 EatenbyaGuru 的建议,我想出了三个正则表达式来涵盖七种可能性
digit_part0 = r"[+-]?[0-9]*\.[0-9]+\s?(?:×\s?10-?[0-9])?"
digit_part1 = r"[+-]?[1-9][0-9]*\s?(?:×\s?10-?[0-9])?"
digit_part2 = r"[+-]?[1-9][0-9]*[\s,][0-9]+(?:\.[0-9]*)?"
其中 digit_prat0
用于涵盖案例 #3、4 和 6; digit_part1
用于涵盖案例 #5 和案例 7; digit_part2
用于覆盖情况 #1、2。此时,digit_part0
和 digit_part1
之间可能存在重叠情况。
更新 2
现在我构建了一个正则表达式,有望捕获所有可能性
[+-]?(?:[1-9][0-9]+[\s,])?(?:[0-9]+\.)?[0-9]+\s?(?:×\s?10-?[0-9])?
没有安全的通用方法来执行此操作。您只能根据输入数据开展工作并涵盖其中的案例,这始终意味着您需要适应并做出妥协。
以下正则表达式针对样本中定义的数字:
-?\d[\d .,]*\b
并像这样匹配:
- 10 000 (→
10 000
) - 10,000 (→
10,000
) - -3.33 × 10-3 (→
-3.33
,10
,-3
) - 8.×104(→
8
,104
) - 5×104 (→
5
,104
) - 12.123 (→
12.123
) - 12 (→
12
)
如果你想匹配表达式,你可以说X(?:YX)*
,其中X
是数字的正则表达式,Y
允许的运算符的正则表达式,包括周围的绒毛(例如空格)。
因此,如果我们说现在允许的运算符应该是 \.? *(?:×|-) *
(\.
只是为了涵盖您的 8.× 104
情况),您最终会得到:
-?\d[\d .,]*\b(?:\.? *(?:×|-) *-?\d[\d .,]*\b)*
│ | | || |
└─────X──────┘(?:└─────Y──────┘└─────X──────┘)*
匹配如下:
- 10 000 (→
10 000
) - 10,000 (→
10,000
) - -3.33 × 10-3 (→
-3.33 × 10-3
) - 8.×104(→
8.× 104
) - 5×104 (→
5×104
) - 12.123 (→
12.123
) - 12 (→
12
)
我相信您会发现这不够具体或不够通用的情况。根据需要更新“数字”和“运算符”组件。
例如,-?\d[\d .,]*\b
可能过于简单。没有什么可以阻止它匹配 1,,,,,0
或 10000.0,0.0,0
之类的东西。如果这样的事情不会出现在您的输入数据中,那么它可能没问题。如果您需要使其更智能以便识别合法数字分组或丢弃无意义的分隔符组合,请使其更智能。这一切都取决于。