如何从收据收据的 Google OCR 转储文本 csv 文件中提取特定数据

How can I extract specific data from an Google OCR dump text csv file of till receipts

我只是学习 Python 机器学习的初学者。我在自学NLP,遇到了问题。我有一个带有 OCR 读取收据(100 次观察)的 csv 文件……每个单元格一张收据。一张收据的示例如下(csv中的信息以这种方式读取):

text = '''ㅎㅎ
Fresh Food
The fresh food people
5619 Lorem PH: 00 0000 0000
204 Some Road
TAX INVOICE - ABN 88 000 014 675
Gift Card Visa Varbl 20to500Dollars
Potato White Washed 2Kg
Nescafe Coffee Blend 43 50g
^HToblerone Milk Chocolate Bar 50g
^HOreo Cookie Original 133g
#M&Ms Crispy 145g
*HRed Rock Deli Portgse Chicken 150g
^HWrigleys Extra Pepprmint 14pc 27g
Qty
57.95
3.50
5.00
0.90
1.50
4.50
3.50
2 @ .80
each
3.60
.45
9 SUBTOTAL
TOTAL
.45
REWARDS SAVINGS
.00
Fresh Food
5619
Lorem'''

虽然收据通常是非结构化的(即有些收据比其他收据有更多的行和辅助信息),但有 3 件事在其布局中非常结构化,我正在尝试提取该信息:小计金额(总是出现在 TOTAL 之前),TOTAL 金额(总是出现在 SUBTOTAL 之后),以及购买的商品列表(总是出现在 ABN 号码之后并在 'Qty' 之前结束)

我是这样开始的:

re.split(r'\s+', text) --->splits the string into a list of words

['ã£Â…Žã…Ž', 'Freah', 'Food', 'The', 'fresh', 'food', 'people', '5619', 'Unley', 'PH:', '00', '0000', '0000', '204', 'Some', 'Road', 'TAX', 'INVOICE', '-', 'ABN', '88', '000', '014', '675', 'Gift', 'Card', 'Visa', 'Varbl', '20to500Dollars', 'Potato', 'White', 'Washed', '2Kg', 'Nescafe', 'Coffee', 'Blend', '43', '50g', '^HToblerone', 'Milk', 'Chocolate', 'Bar', '50g', '^HOreo', 'Cookie', 'Original', '133g', '#M&Ms', 'Crispy', '145g', '*HRed', 'Rock', 'Deli', 'Portgse', 'Chicken', '150g', '^HWrigleys', 'Extra', 'Pepprmint', '14pc', '27g', 'Qty', '57.95', '3.50', '5.00' , '0.90', '1.50', '4.50', '3.50', '2', '@', '1.80 美元', 'each', '3.60', '80.45 美元', '9', 'SUBTOTAL', 'TOTAL', '$80.45', 'REWARDS', 'SAVINGS', '$10.00', 'Fresh', 'Food', '5619', 'UNLEY' , 'SA', 'TCDM', 'ID.', 'Thank', 'you', 'tor', 'shopping', 'with', 'us', 'STORE', '5619', 'POS', '065', 'TRANS', '8660', '13:39', '04/08/2021']

x = re.search('SUBTOTAL', text)
print(x.group())
y = re.search('TOTAL', text)
print(y.group())

小计

总计

现在我正在尝试获取金额...所以小计前的数字 (9) 和总计后的数字 ($80.45)...我尝试遍历文本列表并尝试正则表达式,但我无法得到我想要的....此外,我对如何提取购买的物品感到困惑('ABN 88 000 014 675' 和 'Qty' 之间的文本字符串,尽管拆分已经拆分了 ABN 和数字也是不同的词......所以它又是一个问题。

我做错了什么?我该如何解决这个问题? 我想到了遍历文本:

for sentence in text:

(但再一次,那又怎样...如何到达我想要的行)

任何帮助将不胜感激。

你可以使用正则表达式

(?s)^(?=.* ABN \d{2}(?: \d{3}){3}\n(?P<products>.*\n)Qty\n).*\n$(?P<subtotal>\d+\.\d{2})\n\d+ SUBTOTAL\.*\nTOTAL\n$(?P<total>\d+\.\d{2})\n

捕获组 products 包含产品的子字符串:

"Gift Card Visa Varbl 20to500Dollars\nPotato White Washed 2Kg\nNescafe Coffee Blend 43 50\n^HToblerone Milk Chocolate Bar 50g\n^HOreo Cookie Original 133\n#M&Ms Crispy 145g\n*HRed Rock Deli Portgse Chicken 150g\n^HWrigleys Extra Pepprmint 14pc 27g(?.*\nz"

如果需要,可以夹在换行符上。

捕获组 subtotal 包含小计:

9

捕获组total包含总数:

80.45

Demo

问题没有指定产品的位置。据推测,它可以在小计和总计之前或之后。正是出于这个原因,我在字符串开始锚 ^ 之后的正前瞻中捕获了它们。前瞻不会将引擎的内部字符串指针移到字符串开头之外,确保找到小计和总计(如果存在)。

正则表达式执行以下操作。

(?s)             # cause periods to match all chars, including newlines
^                # match beginning of string
(?=              # begin positive lookahead
  .*             # match zero or more chars
  \ ABN\         # match ' ABN '
  \d{2}          # match 2 digits
  (?:            # begin a non-capture group
    \ \d{3}      # match a space followed by 3 digits
  ){3}           # end non-capture group, execute thrice 
  \n             # match newline
  (?P<products>  # begin a capture group named 'products'
    .*           # match zero or more chars including newlines           
    \n           # match newline
  )              # end capture group
  Qty\n          # match 'Qty', newline
)                # end positive lookahead
.*\n             # match zero or more chars, newline
$\d+\.\d{2}\n   # match '$', one or more digits, period, 2 digits, newline
(?P<subtotal>    # begin capture group named 'subtotal'
  \d+            # match one or more digits
)                # end capture group
\ +SUBTOTAL\n    # match one or more spaces, 'SUBTOTAL', newline
TOTAL\n          # match 'TOTAL', newline
$               # match '$'
(?P<total>       # begin capture group named 'total'       
  \d+\.\d{2}     # match one or more digits, period, 2 digits
)                # end capture group
\n               # match newline

我对上面的空格进行了转义,使它们更显眼。