Initial xentral_oss_20.3.c9ffacf

This commit is contained in:
Alex
2021-05-21 08:49:41 +02:00
parent 5406e4a551
commit 34e5ac43d9
18884 changed files with 2109867 additions and 0 deletions
@@ -0,0 +1,63 @@
<?php
namespace Xentral\Modules\HocrParser\Finder;
use Xentral\Modules\HocrParser\Data\BoundingBox;
use Xentral\Modules\HocrParser\Data\BoundingBoxCollection;
class BoundingBoxFinder
{
/** @var BoundingBoxCollection $boxes */
private $boxes;
/** @var array|RelativePositionFinderFacet[] $criteria */
private $criteria;
/** @var array $currencies */
private $currencies;
/**
* @param BoundingBoxCollection $boxes
* @param array|RelativePositionFinderFacet[] $criteria
* @param array $validCurrencies
*/
public function __construct(BoundingBoxCollection $boxes, array $criteria, array $validCurrencies = [])
{
$this->boxes = $boxes;
$this->criteria = $criteria;
$this->currencies = $validCurrencies;
}
/**
* @return array
*/
public function Find()
{
$search = [];
$result = [];
// Alle Boxen finden die den jeweiligen Suchbegriff enthalten
/** @var BoundingBox $box */
foreach ($this->boxes->GetBoxes() as $box) {
foreach ($this->criteria as $searchKey => $criteria) {
$result[$searchKey] = null;
// Alle Boxen sammeln die den Vorbedingungen entsprechen
if ($criteria->MatchPreCondition($box->GetData('text'))) {
$search[$searchKey]['boxes'][] = $box;
$search[$searchKey]['criteria'] = $criteria;
}
}
}
// Schauen welche der Kandidaten die genauen Vorgaben erfüllt; der erste Treffer gewinnt
foreach ($search as $searchKey => $searchInfo) {
$criteria = $searchInfo['criteria'];
$candidates = $searchInfo['boxes'];
$result[$searchKey] = $criteria->Select($candidates, $this->boxes);
}
return $result;
}
}
@@ -0,0 +1,75 @@
<?php
namespace Xentral\Modules\HocrParser\Finder;
use Xentral\Modules\HocrParser\Data\BoundingBox;
use Xentral\Modules\HocrParser\Data\BoundingBoxCollection;
class CurrencyCodeFinderFacet implements FinderFacetInterface
{
/** @var array $validCodes */
private $validCodes;
/**
* @param array $validCodes Array mit gültigen Währungscodes (drei-stelliger ISO-Code)
*/
public function __construct(array $validCodes = ['EUR'])
{
$this->validCodes = $validCodes;
}
/**
* @param string $text
*
* @return bool
*/
public function MatchPreCondition($text)
{
if (!$this->IsCurrencyLikeValue($text)) {
return false;
}
if (!$this->IsValidCurrency($text)) {
return false;
}
return true;
}
/**
* @param string $value
*
* @return bool
*/
private function IsCurrencyLikeValue($value)
{
return (bool)preg_match('/^[A-Z]{3}$/', $value);
}
/**
* @param string $value
*
* @return bool
*/
private function IsValidCurrency($value)
{
return in_array($value, $this->validCodes, true);
}
/**
* @param array|BoundingBox[] $candidates
* @param BoundingBoxCollection $boxes
*
* @return string|false
*/
public function Select(array $candidates, BoundingBoxCollection $boxes)
{
if (empty($candidates)) {
return false;
}
// Einfach das erste Ergebnis zurückliefern;
// In den PreConditions wurde schon sichergestellt dass es eine gültige Währung ist
return $candidates[0]->GetData('text');
}
}
@@ -0,0 +1,12 @@
<?php
namespace Xentral\Modules\HocrParser\Finder;
use Xentral\Modules\HocrParser\Data\BoundingBoxCollection;
interface FinderFacetInterface
{
public function MatchPreCondition($text);
public function Select(array $candidates, BoundingBoxCollection $boxes);
}
@@ -0,0 +1,123 @@
<?php
namespace Xentral\Modules\HocrParser\Finder;
use Xentral\Modules\HocrParser\Exception\InvalidArgumentException;
class PatternMatcher
{
public const PATTERN_DOCUMENT_NUMBER = 'documentnumber';
public const PATTERN_MONEY = 'money';
public const PATTERN_DATE = 'date';
public const PATTERN_DEFAULT = 'default';
/** @var array $validPatterns */
private static $validPatterns = [
self::PATTERN_DOCUMENT_NUMBER,
self::PATTERN_MONEY,
self::PATTERN_DATE,
self::PATTERN_DEFAULT,
];
/** @var string $pattern */
private $pattern;
/**
* @param string $pattern
*/
public function __construct($pattern = self::PATTERN_DEFAULT)
{
if (!in_array($pattern, self::$validPatterns, true)) {
throw new InvalidArgumentException(sprintf('Pattern "%s" is not allowed.', $pattern));
}
$this->pattern = $pattern;
}
/**
* @param string $value
*
* @return bool
*/
public function Match($value)
{
$value = trim((string)$value);
if (empty($value)) {
return false;
}
switch ($this->pattern) {
case self::PATTERN_DATE:
return $this->IsDateLikeValue($value);
break;
case self::PATTERN_MONEY:
return $this->IsMoneyLikeValue($value);
break;
case self::PATTERN_DOCUMENT_NUMBER:
return $this->IsDocumentNumberLikeValue($value);
break;
case self::PATTERN_DEFAULT:
return $this->IsCandidateValue($value);
break;
}
return false;
}
/**
* @param string $value
*
* @return bool
*/
private function IsDateLikeValue($value)
{
return (bool)preg_match('/\d{1,2}\.\d{1,2}\.\d{2,4}/', $value);
}
/**
* @param string $value
*
* @return bool
*/
private function IsMoneyLikeValue($value)
{
// Mit Tausendertrenner: z.B.: 11.111,11 oder 11,111.11
$withThousands = (bool)preg_match('/\d+[\.,]\d{3}[\.,]{1}\d{2}$/', $value);
if ($withThousands) {
return true;
}
// Ohne Tausendertrenner: z.B.: 1111111,11 oder 1111111.11
return (bool)preg_match('/^\d+[\.,]{1}\d{2}$/', $value);
}
/**
* @param $value
*
* @return bool
*/
private function IsDocumentNumberLikeValue($value)
{
// Nur Grossbuchstaben, Zahlen, Minus und Unterstrich sind erlaubt
$containsInvalidChars = (bool)preg_match('/[^A-Z0-9\-_]+/', $value);
if ($containsInvalidChars) {
return false;
}
return (bool)preg_match('/\d{4,}/', $value);
}
/**
* @param string $value
*
* @return bool
*/
private function IsCandidateValue($value)
{
return $this->IsDateLikeValue($value)
|| $this->IsDocumentNumberLikeValue($value)
|| $this->IsMoneyLikeValue($value);
}
}
@@ -0,0 +1,111 @@
<?php
namespace Xentral\Modules\HocrParser\Finder;
use Xentral\Modules\HocrParser\Data\BoundingBox;
use Xentral\Modules\HocrParser\Data\BoundingBoxCollection;
use Xentral\Modules\HocrParser\Exception\InvalidArgumentException;
class RelativePositionFinderFacet implements FinderFacetInterface
{
const DIRECTION_LEFT = 'left';
const DIRECTION_RIGHT = 'right';
const DIRECTION_ABOVE = 'above';
const DIRECTION_BELOW = 'below';
/** @var array $validDirections */
private static $validDirections = [
self::DIRECTION_ABOVE,
self::DIRECTION_RIGHT,
self::DIRECTION_BELOW,
self::DIRECTION_LEFT,
];
/** @var string $text */
private $text;
/** @var PatternMatcher $matcher */
private $matcher;
/** @var string $direction */
private $direction;
/**
* @param string $searchText
* @param string $direction
* @param string $pattern
*/
public function __construct($searchText, $direction, $pattern)
{
if (!in_array($direction, self::$validDirections, true)) {
throw new InvalidArgumentException(sprintf('Direction "%s" is not allowed.', $direction));
}
$this->matcher = new PatternMatcher($pattern);
$this->text = trim($searchText);
$this->direction = $direction;
}
/**
* @param string $text
*
* @return bool
*/
public function MatchPreCondition($text)
{
return $text === $this->text;
}
/**
* @param array|BoundingBox[] $candidates
* @param BoundingBoxCollection $boxes
*
* @return string|false
*/
public function Select(array $candidates, BoundingBoxCollection $boxes)
{
foreach ($candidates as $candidate) {
$coords = $candidate->GetCenterPoint();
/** @var BoundingBox $nearestBox */
$nearestBox = false;
switch ($this->direction) {
case self::DIRECTION_RIGHT:
$nearestBox = $boxes->GetNearestBoxRightFromPoint($coords['x'], $coords['y']);
break;
case self::DIRECTION_LEFT:
$nearestBox = $boxes->GetNearestBoxLeftFromPoint($coords['x'], $coords['y']);
break;
case self::DIRECTION_ABOVE:
$nearestBox = $boxes->GetNearestBoxAboveFromPoint($coords['x'], $coords['y']);
break;
case self::DIRECTION_BELOW:
$nearestBox = $boxes->GetNearestBoxBelowFromPoint($coords['x'], $coords['y']);
break;
}
if ($nearestBox === false) {
continue;
}
// Prüfen ob Wert einem bestimmten Muster folgt
$patternMatching = $this->IsPatternMatching($nearestBox->GetData('text'));
if ($patternMatching) {
return $nearestBox->GetData('text');
}
}
return false;
}
/**
* @param string $value
*
* @return bool
*/
private function IsPatternMatching($value)
{
return $this->matcher->Match($value);
}
}