在 OCR 获得的收据中查找总数 - PHP

Posted

技术标签:

【中文标题】在 OCR 获得的收据中查找总数 - PHP【英文标题】:Find the total in a receipt got by OCR - PHP 【发布时间】:2018-11-18 04:45:36 【问题描述】:

我在通过 API 视觉获得的收据字符串中查找用户支付的总金额时遇到问题。

例如:

$testo2 = "Del burger Sr Via Carlo del Prete 106/d 50127 FIRENZE C.F. E P.IVA 08380120482 BRUNCH MAMMAMIA ONION RINGS SPICCHI PATATE ACQUA 0.5L TAVOLO 88 EURO 6,50 6,50 4,00 3,00 1,00 TOTALE EURO CONTANTI 21,00 21,00 NR.0057 23/05/18 20:21 MF U1 72005985";

为了找到总数,我试图在一个中搜索点或逗号(一些收据有点和另一个逗号),然后检查点或逗号后面是否有两个数字,然后搜索数字在逗号之前,直到找到找到的字符是一个数字。然后我将这些值放入一个数组中,并以这样的方式反转它以组成一个完整的价格字符串(包括逗号后面的值)。然后将价格输入到一个数组中。

 for($i = 1; $i <= $lenghtTesto2 - 1; $i++)

   if($testo2[$i] == "." || $testo2[$i] == ",")
   
      if($testo2[$i + 1] == "0" || $testo2[$i + 1] == "1" || $testo2[$i + 1] == "2" || $testo2[$i + 1] == "3" || $testo2[$i + 1] == "4" || $testo2[$i + 1] == "5" || $testo2[$i + 1] == "6" || $testo2[$i + 1] == "7" || $testo2[$i + 1] == "8" || $testo2[$i + 1] == "9")
      
         if($testo2[$i + 2] == "0" || $testo2[$i + 2] == "1" || $testo2[$i + 2] == "2" || $testo2[$i + 2] == "3" || $testo2[$i + 2] == "4" || $testo2[$i + 2] == "5" || $testo2[$i + 2] == "6" || $testo2[$i + 2] == "7" || $testo2[$i + 2] == "8" || $testo2[$i + 2] == "9")
          

          $check = true;
          while($check)
          
              if($testo2[$i - $j] == "0" || $testo2[$i - $j] == "1" || $testo2[$i - $j] == "2" || $testo2[$i - $j] == "3" || $testo2[$i - $j] == "4" || $testo2[$i - $j] == "5" || $testo2[$i - $j] == "6" || $testo2[$i - $j] == "7" || $testo2[$i - $j] == "8" || $testo2[$i - $j] == "9")
                        


                array_push($arrPrezzi_invertiti, $testo2[$i - $j]);

                $j++;

              
              else
              
                 $prezzo = "";
                 $totaleFinale = "";
                 $dopoPunto1 = $testo2[$i + 1];
                 $dopoPunto2 = $testo2[$i + 2];
                 $j = 1;
                 $lenght_arrPrezzi_invertiti = count($arrPrezzi_invertiti);


                 for($k = $lenght_arrPrezzi_invertiti - 1; $k >= 0; $k--)
                 
                     $totaleFinale .= $arrPrezzi_invertiti[$k];

                 

                 $prezzo = $totaleFinale . "." . $dopoPunto1 . $dopoPunto2;

                 array_push($array, $prezzo);

                 $check = false;
                 
                        
     
  


钱是 6,50 6,50 4,00 3,00 1,00 21,00 21,00

提前致谢。

【问题讨论】:

首先,有什么问题?你没有指定。其次,您是否尝试过使用正则表达式?它更干净。并请具体说明字符串中列出的钱在哪里。并非所有人都懂意大利语 您是在尝试创建通用解决方案还是字符串始终采用这种精确格式? 不就是TOTALE这个词后面的第一个数字吗(假设CONTANTE表示现金,也可以是一个不同的词(或多个词),所以你可能想要灵活处理那?所以我认为你想隔离从 TOTALE 之后的第一个数字到之后的第一个空格的所有内容。 在第二张收据上,是所有的数据还是你把它剪掉了,请用你的真实字符串而不是图片发布代码,我需要使用你的真实字符串进行测试。 第二个有不同的格式,没有你说会一直存在的这个文本。 【参考方案1】:

使用 preg_match();

您必须将可能的单词组合添加到[\sEURO|\sCONTANTI|\sECT.]

无论如何,这会给你一个想法。修补它,直到你让它按你想要的方式工作。

$testo2 = "Del burger Sr Via Carlo del Prete 106/d 50127 FIRENZE C.F. E P.IVA 08380120482 BRUNCH MAMMAMIA ONION RINGS SPICCHI PATATE ACQUA 0.5L TAVOLO 88 EURO 6,50 6,50 4,00 3,00 1,00 TOTALE EURO CONTANTI 21,00 21,00 NR.0057 23/05/18 20:21 MF U1 72005985";
$testo2 = preg_replace('/\s1,/', ' ', $testo2);
preg_match('/[\s\S]0,TOTALE\s[\sEURO|\sCONTANTI]0,\s(.*?)\s/', $testo2, $match);

echo $match[1];  //<--- Outputs "21,00"

第二种解决方案

我相信你可以疯狂地使用正则表达式并得到一些工作,但我们需要多个示例来借鉴。一个更好的想法可能是假设总金额始终是收据上的最高金额。如果是这种情况,我们可以这样做:

function getReceiptTotal($receipt)

  preg_match_all('/\d+[\.,]\d+\s/', $receipt, $match);

  $comma = preg_match('/,/', $match[0][0]) ? TRUE : FALSE;

  for($i = 0; $i < count($match[0]); $i++)

    $match[0][$i] = trim($match[0][$i]);

    if($comma)

      $temp[] = preg_replace('/,/', '.', $match[0][$i]);

     

  

  sort($temp);

  $total = end($temp);

  if($comma)

    return preg_replace('/\./', ',', $total);


   else 

    return $total;

    



echo getReceiptTotal($testo2); //Will output "21,00".

这应该适用于您的所有收据类型。

【讨论】:

$testo2 是收据的一个例子,但是使用 OCR 的用户可以从不同的收据中获取文本。这个解决方案是通用的还是特定的? 你需要告诉我们!我们正在尝试寻找匹配的模式。这适用于价格在单词totale和单词(EURO或CONTANTI)之后下降的任何收据数据。 @AlessioRaddi - 下定决心。字符串总是采用完全相同的格式(相同的文本)还是可以不同?你陈述不同的事情。首先你说“一些收据有一个点和另一个逗号”,然后你说它将是这种精确的格式。这将解决您的问题,确切的格式并处理点和逗号。如果其他情况有所不同,您需要告诉我们,否则您既浪费了您的时间,也浪费了我们的时间。 @MagnusEriksson 收据可以包含点或逗号。我刚刚检查过TOTALE EURO CONTANTI 可能不同,它们的值可能会在它们之前和之后移动 @MagnusEriksson 我在我的问题中添加了两个不同收据的示例【参考方案2】:

要查找总数,您可以使用preg_match。

TOTALE EURO CONTANTI\s*\K\d+[.,]\d+

或者在 TOTALE EURO CONTANTI 之间有一个或多个空白字符:

TOTALE\s+EURO\s+CONTANTI\s+\K\d+[.,]\d+

您可以匹配TOTALE EURO CONTANTI,后跟零个或多个空格字符\s*,然后重置匹配的起点。然后使用字符类匹配一个或多个数字、逗号或点,后跟一个或多个数字\d+[.,]\d+

$re = '/TOTALE EURO CONTANTI\s*\K\d+,\d+/';
$str = 'Del burger Sr Via Carlo del Prete 106/d 50127 FIRENZE C.F. E P.IVA 08380120482 BRUNCH MAMMAMIA ONION RINGS SPICCHI PATATE ACQUA 0.5L TAVOLO 88 EURO 6,50 6,50 4,00 3,00 1,00 TOTALE EURO CONTANTI 21,00 21,00 NR.0057 23/05/18 20:21 MF U1 72005985';

preg_match($re, $str, $matches);
echo $matches[0]; // 21,00

Demo

【讨论】:

@MagnusEriksson 感谢您的评论。我已经用一个匹配点或逗号的字符类更新了我的答案。 我在我的问题中添加了两张不同收据的例子

以上是关于在 OCR 获得的收据中查找总数 - PHP的主要内容,如果未能解决你的问题,请参考以下文章

使用Tesseract和OpenCV构建自动收据扫描仪

PHP怎么获得mysql分组后记录查询总数。

在 Apple iOS 应用购买服务器到服务器通知沙箱中未获得统一收据

SKReceiptReceiptRequest - 在模拟器上,仅调用 request:didFailWithError 方法。我无法让我的应用获得沙盒收据

查找数组的总数

PHP Azure OCR - 在数组中转换 JSON