Python - 匹配和解析包含 numeric/currency 金额的字符串
Python - match and parse strings containing numeric/currency amounts
假设我在 python 中有以下字符串(输入):
1) "$ 1,350,000"
2) "1.35 MM $"
3) "$ 1.35 M"
4)1350000
(现在是数值)
虽然字符串表示形式不同,但显然数字是相同的。我怎样才能实现字符串匹配,或者换句话说,将它们归类为相等的字符串?
一种方法是使用正则表达式对可能的模式进行建模。不过可能有一种情况是我没有想到的。
有人看到这个问题的 NLP 解决方案吗?
谢谢
这不是 NLP 问题,只是正则表达式的工作,加上一些忽略顺序的代码,并查找已知缩写的字典 (/ontology),例如 "MM".
- 首先,您可以完全忽略此处的“$”字符(除非您需要消除与其他货币或符号的歧义)。
- 所以这一切归结为解析数字格式,并映射 'M'/'MM'/'million' -> 1e6 乘数。并以与顺序无关的方式进行解析(例如,乘数、货币符号和金额可以以任何相对顺序出现,或者根本不出现)
这是一些工作代码:
def parse_numeric_string(s):
if isinstance(s, int): s = str(s)
amount = None
currency = ''
multiplier = 1.0
for token in s.split(' '):
token = token.lower()
if token in ['$','€','£','¥']:
currency = token
# Extract multipliers from their string names/abbrevs
if token in ['million','m','mm']:
multiplier = 1e6
# ... or you could use a dict:
# multiplier = {'million': 1e6, 'm': 1e6...}.get(token, 1.0)
# Assume anything else is some string format of number/int/float/scientific
try:
token = token.replace(',', '')
amount = float(token)
except:
pass # Process your parse failures...
# Return a tuple, or whatever you prefer
return (currency, amount * multiplier)
parse_numeric_string("$ 1,350,000")
parse_numeric_string("1.35 MM $")
parse_numeric_string("$ 1.35 M")
parse_numeric_string(1350000)
- 对于国际化,您可能需要注意
,
和 .
作为千位分隔符和小数点可以切换,或者 '
作为(阿拉伯语)千位分隔符。还有一个第三方 Python 包 'parse',例如parse.parse('{fn}', '1,350,000')
(与format()
相反)
- 使用 ontology 或通用 NLP 库可能会比它的价值更麻烦。例如,您需要在 "accounting abbreviation for millions" 中的 'mm' 与 "millimeters" 和 'Megameters, 10^6 meters' 中的 'Mm' 之间消除歧义,后者几乎从未使用过但距离的有效公制单位。因此,较少的通用性可能更适合这项任务。
- 您还可以使用基于字典的方法来映射其他货币符号,例如'dollars','US','USD','US$','EU'...
- 这里我在空格上进行了标记,但您可能希望在任何 word/numeric/whitespace/punctuation 边界上进行标记,以便您可以解析例如
USD1.3m
考虑创建一个例程,将字符串输入(可以是任何 4 种给定格式)与 4 种正则表达式模式相匹配,如下所示:
对于“1,350,000 美元”:
(?<=$ )([\d,]+)
对于“1.35 MM $”:
([\d\.]+)(?= MM $)
对于“135 万美元”:
(?<=$ )([\d\.]+)(?= M)
对于 1350000:
([\d]+)
然后将这些匹配转换成整数返回并与其他匹配。
提供的正则表达式模式将仅匹配字符串的数字逗号和小数位(通过使用先行和后行)。
注意: 根据匹配的正则表达式,将要求对提取的数字进行相应处理。 (例如,“$ 1.35 M”中的 1.35 需要乘以 1000000 才能返回)
有趣的问题,这是我的解决方案。
你可以写一些 class 来寻找潜在的匹配项,将它们分隔成一个数量和一个单位,然后尝试转换它们:
import re, locale, math
# us
locale.setlocale(locale.LC_ALL, 'en_US')
from locale import atof
data = """
Say I have the following strings (inputs) in python:
1) "$ 1,350,000" 2) "1.35 MM $" 3) "$ 1.35 M" 4) 1350000 (now it is a numeric value)
Obviously the number is the same although the string representation is different. How can I achieve a string matching or in other words classify them as equal strings?
One way would be to model -using regular expressions- the possible patterns. However there might be a case that I haven't thought of.
Does someone see a NLP solution to this problem?
Thanks
here might be some other digits: 1.234
"""
class DigitMiner:
def __init__(self):
self.numbers = []
def convert(self, amount, unit):
if unit in ['M', 'MM']:
amount *= 10**6
elif unit in ['K']:
amount *= 10**3
else:
pass
return amount
def search(self, string=None):
rx = re.compile(r'''
(?P<amount>\b\d[\d.,]+\b)\s*
(?P<unit>M*)''', re.VERBOSE)
for match in rx.finditer(string):
amount = self.convert(atof(match.group('amount')), match.group('unit'))
if amount not in self.numbers:
self.numbers.append(amount)
dm = DigitMiner()
dm.search(data)
print(dm.numbers)
这产生:
[1350000.0, 1.234]
请注意,locale.atof()
将字符串转换为浮点数,遵循 LC_NUMERIC
设置。
假设我在 python 中有以下字符串(输入):
1) "$ 1,350,000"
2) "1.35 MM $"
3) "$ 1.35 M"
4)1350000
(现在是数值)
虽然字符串表示形式不同,但显然数字是相同的。我怎样才能实现字符串匹配,或者换句话说,将它们归类为相等的字符串?
一种方法是使用正则表达式对可能的模式进行建模。不过可能有一种情况是我没有想到的。
有人看到这个问题的 NLP 解决方案吗?
谢谢
这不是 NLP 问题,只是正则表达式的工作,加上一些忽略顺序的代码,并查找已知缩写的字典 (/ontology),例如 "MM".
- 首先,您可以完全忽略此处的“$”字符(除非您需要消除与其他货币或符号的歧义)。
- 所以这一切归结为解析数字格式,并映射 'M'/'MM'/'million' -> 1e6 乘数。并以与顺序无关的方式进行解析(例如,乘数、货币符号和金额可以以任何相对顺序出现,或者根本不出现)
这是一些工作代码:
def parse_numeric_string(s):
if isinstance(s, int): s = str(s)
amount = None
currency = ''
multiplier = 1.0
for token in s.split(' '):
token = token.lower()
if token in ['$','€','£','¥']:
currency = token
# Extract multipliers from their string names/abbrevs
if token in ['million','m','mm']:
multiplier = 1e6
# ... or you could use a dict:
# multiplier = {'million': 1e6, 'm': 1e6...}.get(token, 1.0)
# Assume anything else is some string format of number/int/float/scientific
try:
token = token.replace(',', '')
amount = float(token)
except:
pass # Process your parse failures...
# Return a tuple, or whatever you prefer
return (currency, amount * multiplier)
parse_numeric_string("$ 1,350,000")
parse_numeric_string("1.35 MM $")
parse_numeric_string("$ 1.35 M")
parse_numeric_string(1350000)
- 对于国际化,您可能需要注意
,
和.
作为千位分隔符和小数点可以切换,或者'
作为(阿拉伯语)千位分隔符。还有一个第三方 Python 包 'parse',例如parse.parse('{fn}', '1,350,000')
(与format()
相反) - 使用 ontology 或通用 NLP 库可能会比它的价值更麻烦。例如,您需要在 "accounting abbreviation for millions" 中的 'mm' 与 "millimeters" 和 'Megameters, 10^6 meters' 中的 'Mm' 之间消除歧义,后者几乎从未使用过但距离的有效公制单位。因此,较少的通用性可能更适合这项任务。
- 您还可以使用基于字典的方法来映射其他货币符号,例如'dollars','US','USD','US$','EU'...
- 这里我在空格上进行了标记,但您可能希望在任何 word/numeric/whitespace/punctuation 边界上进行标记,以便您可以解析例如
USD1.3m
考虑创建一个例程,将字符串输入(可以是任何 4 种给定格式)与 4 种正则表达式模式相匹配,如下所示:
对于“1,350,000 美元”:
(?<=$ )([\d,]+)
对于“1.35 MM $”:
([\d\.]+)(?= MM $)
对于“135 万美元”:
(?<=$ )([\d\.]+)(?= M)
对于 1350000:
([\d]+)
然后将这些匹配转换成整数返回并与其他匹配。
提供的正则表达式模式将仅匹配字符串的数字逗号和小数位(通过使用先行和后行)。
注意: 根据匹配的正则表达式,将要求对提取的数字进行相应处理。 (例如,“$ 1.35 M”中的 1.35 需要乘以 1000000 才能返回)
有趣的问题,这是我的解决方案。
你可以写一些 class 来寻找潜在的匹配项,将它们分隔成一个数量和一个单位,然后尝试转换它们:
import re, locale, math
# us
locale.setlocale(locale.LC_ALL, 'en_US')
from locale import atof
data = """
Say I have the following strings (inputs) in python:
1) "$ 1,350,000" 2) "1.35 MM $" 3) "$ 1.35 M" 4) 1350000 (now it is a numeric value)
Obviously the number is the same although the string representation is different. How can I achieve a string matching or in other words classify them as equal strings?
One way would be to model -using regular expressions- the possible patterns. However there might be a case that I haven't thought of.
Does someone see a NLP solution to this problem?
Thanks
here might be some other digits: 1.234
"""
class DigitMiner:
def __init__(self):
self.numbers = []
def convert(self, amount, unit):
if unit in ['M', 'MM']:
amount *= 10**6
elif unit in ['K']:
amount *= 10**3
else:
pass
return amount
def search(self, string=None):
rx = re.compile(r'''
(?P<amount>\b\d[\d.,]+\b)\s*
(?P<unit>M*)''', re.VERBOSE)
for match in rx.finditer(string):
amount = self.convert(atof(match.group('amount')), match.group('unit'))
if amount not in self.numbers:
self.numbers.append(amount)
dm = DigitMiner()
dm.search(data)
print(dm.numbers)
这产生:
[1350000.0, 1.234]
请注意,
locale.atof()
将字符串转换为浮点数,遵循 LC_NUMERIC
设置。