19std::string normalizeAlphaNumeric(
const std::string &value) {
20 std::string normalized;
21 normalized.reserve(value.size());
23 if ((c >=
'a' && c <=
'z') || (c >=
'0' && c <=
'9'))
24 normalized.push_back(
static_cast<char>(c));
29bool looksLikeAmountToken(
const std::string &token) {
30 const auto separator = token.find_last_of(
".,");
31 if (separator == std::string::npos || separator == 0 ||
32 separator + 3 != token.size())
35 const auto isDigit = [](
unsigned char c) {
return c >=
'0' && c <=
'9'; };
36 if (!isDigit(
static_cast<unsigned char>(token[separator + 1])) ||
37 !isDigit(
static_cast<unsigned char>(token[separator + 2])))
40 bool hasIntegralDigit =
false;
41 for (
size_t i = 0; i < separator; ++i) {
42 const unsigned char c =
static_cast<unsigned char>(token[i]);
44 hasIntegralDigit =
true;
47 if (c !=
'.' && c !=
',')
51 return hasIntegralDigit;
54bool containsAmountToken(
const std::string &value) {
58 [](
const std::string &token) { return looksLikeAmountToken(token); });
72 std::vector<std::string> normalizedTokens;
73 normalizedTokens.reserve(toks.size());
74 for (
const auto &token : toks)
75 normalizedTokens.push_back(normalizeAlphaNumeric(token));
77 static const std::array<std::string, 7> noise = {
78 "kontoauszug",
"auszugnr",
"seitenr",
"ustidnr",
79 "ansprechpartner",
"telefonnummer",
"kontowahrung",
83 for (
const auto &n : noise) {
84 for (
const auto &t : normalizedTokens) {
98 std::initializer_list<const char *> needlesLower) {
99 for (
auto n : needlesLower) {
100 if (hayLower.find(n) != std::string::npos)
109 l, {
"folgeseite",
"vsa000",
"fil200",
"ktea",
"folgende seite"});
114 if (containsAmountToken(l))
117 const std::initializer_list<const char *> strong = {
119 "einlagensicherungsgesetzes",
121 "der angegebene kontostand",
122 "wertstellung der buchungen",
128 for (
auto p : strong)
129 if (l.find(p) != std::string::npos)
133 if (l.find(
"kontostand") != std::string::npos)
135 if (l.find(
"guthaben") != std::string::npos)
137 if (l.find(
"einlagen") != std::string::npos)
139 if (l.find(
"betrag") != std::string::npos)
141 return weakMatches >= 2;
146 if (l.find(
"angaben zu den umsätzen") != std::string::npos)
148 const bool hasValuta = (l.find(
"valuta") != std::string::npos);
149 const bool hasUmsaetze = (l.find(
"umsätzen") != std::string::npos) ||
150 (l.find(
"umsaetzen") != std::string::npos);
151 const bool hasAngaben = (l.find(
"angaben") != std::string::npos);
152 return hasValuta && (hasUmsaetze || hasAngaben);
156 const auto n = normalizeAlphaNumeric(line);
157 return (n.find(
"zuihrenlasten") != std::string::npos) &&
158 (n.find(
"zuihrengunsten") != std::string::npos);
std::string lowerAscii(std::string s)
Converts ASCII letters in a string to lowercase.
Declares heuristics used to classify statement parser lines.
Declares private string helpers shared across core implementation files.
static bool containsAny(const std::string &hayLower, std::initializer_list< const char * > needlesLower)
bool isTransactionsSectionHeader(const std::string &line)
Detects whether a line marks the start of the transactions section.
bool isPostTransactionFootnote(const std::string &line)
Detects whether a line belongs to the post-transaction footnote area.
bool isFooterLine(const std::string &line)
Detects whether a line marks a footer section.
bool isDebitCreditHeaderLine(const std::string &line)
Detects whether a line looks like a debit/credit table header.
bool isHeaderNoiseLine(const std::string &line)
Detects whether a line looks like header noise.
std::vector< std::string > tokens(const std::string &text)
Splits normalized text into tokens.
std::vector< std::string > splitWhitespace(const std::string &s)
Splits a string on ASCII whitespace.
std::string lowerAscii(std::string s)
Converts ASCII letters in a string to lowercase.
std::string trim(std::string s)
Removes leading and trailing ASCII whitespace from a string.