11 #include <QRegularExpression>
12 #include <QStringBuilder>
18 return removeChars(s, [](QChar c) {
return c == u
' ' || c == u
':' || c == u
'_' || c == u
'-' || c == u
'.'; });
23 return splitStringRefs(s, [](QChar c) {
return c ==
'\n' || c ==
'\r'; });
28 return splitString(s, [](QChar c) {
return c ==
'\n' || c ==
'\r'; });
34 for (
const QChar &c : s)
36 if (
const char latin = c.toLatin1())
38 if ((latin >=
'a' && latin <=
'z') || (latin >=
'A' && latin <=
'Z') ||
39 (latin >=
'0' && latin <=
'9') || allow.contains(latin))
41 result += c.toLatin1();
46 if (latin < 0x10) { result +=
'0'; }
47 result += QByteArray::number(
static_cast<int>(latin), 16);
54 const ushort unicode = c.unicode();
55 if (unicode < 0x0010) { result +=
'0'; }
56 if (unicode < 0x0100) { result +=
'0'; }
57 if (unicode < 0x1000) { result +=
'0'; }
58 result += QByteArray::number(unicode, 16);
67 for (
int i = 0; i < ba.size(); ++i)
72 Q_ASSERT(i < ba.size());
76 Q_ASSERT(i < ba.size());
77 result += QChar(ba.mid(i, 4).toInt(
nullptr, 16));
82 result +=
static_cast<char>(ba.mid(i, 2).toInt(
nullptr, 16));
86 else { result += ba[i]; }
93 static const QString on(
"on");
94 static const QString off(
"off");
100 static const QString yes(
"yes");
101 static const QString no(
"no");
107 static const QString t(
"true");
108 static const QString f(
"false");
114 static const QString e(
"enabled");
115 static const QString d(
"disabled");
121 static const QString n(
"null");
122 static const QString nn(
"not null");
123 return isNull ? n : nn;
128 QString s(
string.trimmed().
toLower());
129 if (s.isEmpty()) {
return false; }
132 const QChar c = s.at(0);
133 if (c ==
'1' || c ==
't' || c ==
'y' || c ==
'x') {
return true; }
134 if (c ==
'0' || c ==
'f' || c ==
'n' || c ==
'_') {
return false; }
136 if (c ==
'e') {
return true; }
137 if (c ==
'd') {
return false; }
140 if (s ==
"on") {
return true; }
147 if (cs == Qt::CaseInsensitive)
151 else if (str1 == str2) {
return 100; }
154 if (str1.isEmpty() || str2.isEmpty()) {
return 0; }
157 const QString aStr = str1.length() >= str2.length() ? str1 : str2;
158 const QString bStr = str1.length() >= str2.length() ? str2 : str1;
161 const auto s1 =
static_cast<double>(aStr.length());
162 const auto s2 =
static_cast<double>(bStr.length());
163 if (aStr.endsWith(bStr, cs)) {
return qRound(s1 / s2 * 100); }
164 if (aStr.startsWith(bStr, cs)) {
return qRound(s1 / s2 * 100); }
167 if (aStr.contains(bStr, cs)) {
return qRound(s1 / s2 * 100); }
171 for (
int p = 0; p < aStr.length(); p++)
173 if (p < bStr.length() && aStr[p] == bStr[p])
180 const int after = p + 1;
181 if (after < bStr.length() && aStr[p] == bStr[after])
188 const int before = p - 1;
189 if (before >= 0 && before < bStr.length() && aStr[p] == bStr[before])
195 return qRound(points / s1 * 100);
198 QString
intToHex(
int value,
int digits)
200 const QString hex(QString::number(value, 16).toUpper());
201 const qsizetype l = hex.length();
202 if (l >= digits) {
return hex.right(digits); }
203 const qsizetype d = digits - l;
204 return QString(d,
'0') + hex;
209 const QString s(candidate.trimmed().toUpper());
210 if (s.isEmpty()) {
return {}; }
211 return s.contains(
' ') ? s.left(s.indexOf(
' ')) : s;
219 static const QString diacriticLetters =
220 QString::fromUtf8(
"ŠŒŽšœžŸ¥µÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿ");
221 static const QStringList noDiacriticLetters(
222 {
"S",
"OE",
"Z",
"s",
"oe",
"z",
"Y",
"Y",
"u",
"A",
"A",
"A",
"A",
"A",
"A",
"AE",
"C",
"E",
223 "E",
"E",
"E",
"I",
"I",
"I",
"I",
"D",
"N",
"O",
"O",
"O",
"O",
"O",
"O",
"U",
"U",
"U",
224 "U",
"Y",
"s",
"a",
"a",
"a",
"a",
"a",
"a",
"ae",
"c",
"e",
"e",
"e",
"e",
"i",
"i",
"i",
225 "i",
"o",
"n",
"o",
"o",
"o",
"o",
"o",
"o",
"u",
"u",
"u",
"u",
"y",
"y" });
228 for (
int i = 0; i < candidate.length(); i++)
230 const QChar c = candidate[i];
231 const qsizetype dIndex = diacriticLetters.indexOf(c);
232 if (dIndex < 0) { output.append(c); }
235 const QString replacement = noDiacriticLetters[dIndex];
236 output.append(replacement);
247 for (
const QChar &c : s)
249 if (c.decompositionTag() == QChar::NoDecomposition) { result.push_back(c); }
252 for (
const QChar &dc : c.decomposition())
254 if (!dc.isMark()) { result.push_back(dc); }
263 return c1.length() == c2.length() && c1.startsWith(c2, Qt::CaseInsensitive);
268 return removeChars(name.toUpper(), [](QChar c) { return !c.isUpper(); });
271 QDateTime
fromStringUtc(
const QString &dateTimeString,
const QString &format)
273 if (dateTimeString.isEmpty() || format.isEmpty()) {
return {}; }
274 QDateTime dt = QDateTime::fromString(dateTimeString, format);
275 if (!dt.isValid()) {
return dt; }
276 dt.setOffsetFromUtc(0);
280 QDateTime
fromStringUtc(
const QString &dateTimeString, Qt::DateFormat format)
282 if (dateTimeString.isEmpty()) {
return {}; }
283 QDateTime dt = QDateTime::fromString(dateTimeString, format);
284 if (!dt.isValid()) {
return dt; }
285 dt.setOffsetFromUtc(0);
289 QDateTime
fromStringUtc(
const QString &dateTimeString,
const QLocale &locale, QLocale::FormatType format)
291 if (dateTimeString.isEmpty()) {
return {}; }
292 QDateTime dt = locale.toDateTime(dateTimeString, format);
293 if (!dt.isValid()) {
return dt; }
294 dt.setOffsetFromUtc(0);
300 if (dateTimeString.isEmpty()) {
return {}; }
304 if (dateTimeString.length() == 17) {
return fromStringUtc(dateTimeString,
"yyyyMMddHHmmsszzz"); }
305 if (dateTimeString.length() == 14) {
return fromStringUtc(dateTimeString,
"yyyyMMddHHmmss"); }
306 if (dateTimeString.length() == 12) {
return fromStringUtc(dateTimeString,
"yyyyMMddHHmm"); }
307 if (dateTimeString.length() == 8) {
return fromStringUtc(dateTimeString,
"yyyyMMdd"); }
319 QDateTime ts =
fromStringUtc(dateTimeString, Qt::ISODateWithMs);
320 if (ts.isValid())
return ts;
323 if (ts.isValid())
return ts;
326 if (ts.isValid())
return ts;
328 ts =
fromStringUtc(dateTimeString, QLocale(), QLocale::LongFormat);
329 if (ts.isValid())
return ts;
331 ts =
fromStringUtc(dateTimeString, QLocale(), QLocale::ShortFormat);
332 if (ts.isValid())
return ts;
341 if (dateTimeString.length() < 8) {
return {}; }
345 int year(QStringView { dateTimeString }.left(4).toInt());
346 int month(QStringView { dateTimeString }.mid(4, 2).toInt());
347 int day(QStringView { dateTimeString }.mid(6, 2).toInt());
349 date.setDate(year, month, day);
351 dt.setOffsetFromUtc(0);
353 if (dateTimeString.length() < 12) {
return dt; }
356 const int hour(QStringView { dateTimeString }.mid(8, 2).toInt());
357 const int minute(QStringView { dateTimeString }.mid(10, 2).toInt());
358 const int second(dateTimeString.length() < 14 ? 0 : QStringView { dateTimeString }.mid(12, 2).toInt());
359 const int ms(dateTimeString.length() < 17 ? 0 : QStringView { dateTimeString }.right(3).toInt());
361 t.setHMS(hour, minute, second, ms);
366 QString
dotToLocaleDecimalPoint(QString &input) {
return input.replace(
'.', QLocale::system().decimalPoint()); }
371 return copy.replace(
'.', QLocale::system().decimalPoint());
374 bool stringCompare(
const QString &c1,
const QString &c2, Qt::CaseSensitivity cs)
376 if (cs == Qt::CaseSensitive) {
return c1 == c2; }
382 if (in.isEmpty()) {
return ignoreEmpty ? QString() : QStringLiteral(
"''"); }
383 return u
'\'' % in % u
'\'';
386 QString
inQuotes(
const QString &in,
bool ignoreEmpty)
388 if (in.isEmpty()) {
return ignoreEmpty ? QString() : QStringLiteral(
"\"\""); }
389 return u
'"' % in % u
'"';
394 if (question.endsWith(
"?")) {
return question; }
395 return question % u
'?';
398 qsizetype
nthIndexOf(
const QString &
string, QChar ch,
int nth, Qt::CaseSensitivity cs)
400 if (nth < 1 ||
string.isEmpty() || nth >
string.length()) {
return -1; }
404 for (
int t = 0; t < nth; ++t)
406 ci =
string.indexOf(ch, from, cs);
407 if (ci < 0) {
return -1; }
409 if (from >=
string.length()) {
return -1; }
414 QString
joinStringSet(
const QSet<QString> &set,
const QString &separator)
416 if (set.isEmpty()) {
return {}; }
417 if (set.size() == 1) {
return *set.begin(); }
418 return set.values().join(separator);
425 for (
const QStringView l : lines)
427 if (l.isEmpty()) {
continue; }
428 const qsizetype i = l.indexOf(
'=');
429 if (i < 0 || i >= l.length() + 1) {
continue; }
431 const QString key = l.left(i).trimmed().toString();
432 const QString value = l.mid(i + 1).toString();
433 if (value.isEmpty()) {
continue; }
434 map.insert(key, value);
441 if (in.size() < 2) {
return in; }
442 if (in.startsWith(
"'") && in.endsWith(
"'")) {
return in.mid(1, in.length() - 2); }
448 if (in.size() < 2) {
return in; }
449 if (in.startsWith(
"\"") && in.endsWith(
"\"")) {
return in.mid(1, in.length() - 2); }
453 QString
removeComments(
const QString &in,
bool removeSlashStar,
bool removeDoubleSlash)
457 thread_local
const QRegularExpression re1(R
"(\/\*(.|\n)*?\*\/)");
458 if (removeSlashStar) { copy.remove(re1); }
460 thread_local
const QRegularExpression re2(
"\\/\\/.*");
461 if (removeDoubleSlash) { copy.remove(re2); }
466 bool containsAny(
const QString &testString,
const QStringList &any, Qt::CaseSensitivity cs)
468 if (testString.isEmpty() || any.isEmpty()) {
return false; }
469 return std::any_of(any.begin(), any.end(), [&](
const QString &a) { return testString.contains(a, cs); });
474 if (in.isEmpty()) {
return true; }
475 const qsizetype c = in.count(quote);
479 double parseFraction(
const QString &fraction,
double failDefault)
481 if (fraction.isEmpty()) {
return failDefault; }
484 double r = failDefault;
485 if (fraction.contains(
'/'))
487 const QStringList parts = fraction.split(
'/');
488 if (parts.size() != 2) {
return failDefault; }
489 const double c = parts.front().trimmed().toDouble(&ok);
490 if (!ok) {
return failDefault; }
492 const double d = parts.last().trimmed().toDouble(&ok);
493 if (!ok) {
return failDefault; }
494 if (qFuzzyCompare(0.0, d)) {
return failDefault; }
499 r = fraction.trimmed().toDouble(&ok);
500 if (!ok) {
return failDefault; }
507 QString n = number.trimmed();
508 if (n.isEmpty()) {
return {}; }
510 qsizetype dp = n.indexOf(
'.');
511 if (dp < 0) { dp = n.indexOf(
','); }
514 while (dp >= 0 && !n.isEmpty())
516 const QChar l = n.at(n.size() - 1);
522 if (l ==
'.' || l ==
',') { n.chop(1); }
526 while (n.startsWith(
"00")) { n.remove(0, 1); }
Free functions in swift::misc.
SWIFT_MISC_EXPORT QString withQuestionMark(const QString &question)
Add a question mark at the end if not existing.
SWIFT_MISC_EXPORT QString simplifyNameForSearch(const QString &name)
Get a simplified upper case name for searching by removing all characters except A-Z.
SWIFT_MISC_EXPORT qsizetype nthIndexOf(const QString &string, QChar ch, int nth=1, Qt::CaseSensitivity cs=Qt::CaseInsensitive)
nth index of ch
SWIFT_MISC_EXPORT QString cleanNumber(const QString &number)
Remove leading 0, trailing 0, " ", and "." from a number.
SWIFT_MISC_EXPORT QString inApostrophes(const QString &in, bool ignoreEmpty=false)
Return string in apostrophes.
SWIFT_MISC_EXPORT QString intToHex(int value, int digits=2)
Int to hex value.
SWIFT_MISC_EXPORT QByteArray utfToPercentEncoding(const QString &s, const QByteArray &allow={}, char percent='%')
Extended percent encoding supporting UTF-16.
SWIFT_MISC_EXPORT QString stripDesignatorFromCompleterString(const QString &candidate)
Strip a designator from a combined string.
SWIFT_MISC_EXPORT QDateTime parseMultipleDateTimeFormats(const QString &dateTimeString)
Parse multiple date time formats.
SWIFT_MISC_EXPORT QString utfFromPercentEncoding(const QByteArray &ba, char percent='%')
Reverse utfFromPercentEncoding.
SWIFT_MISC_EXPORT int fuzzyShortStringComparision(const QString &str1, const QString &str2, Qt::CaseSensitivity cs=Qt::CaseSensitive)
Fuzzy compare for short strings (like ICAO designators)
QString removeChars(const QString &s, F predicate)
Return a string with characters removed that match the given predicate.
SWIFT_MISC_EXPORT QList< QStringView > splitLinesRefs(const QString &s)
Split a string into multiple lines. Blank lines are skipped.
SWIFT_MISC_EXPORT QString removeDateTimeSeparators(const QString &s)
Remove the typical separators such as "-", " ".
SWIFT_MISC_EXPORT QMap< QString, QString > parseIniValues(const QString &data)
Obtain ini file like values, e.g. foo=bar.
SWIFT_MISC_EXPORT QString simplifyByDecomposition(const QString &candidate)
Remove accents / diacritic marks from a string by doing a Unicode decomposition and removing mark cha...
SWIFT_MISC_EXPORT bool caseInsensitiveStringCompare(const QString &c1, const QString &c2)
Case insensitive string compare.
QList< QStringView > splitStringRefs(const QString &s, F predicate)
Split a string into multiple strings, using a predicate function to identify the split points.
SWIFT_MISC_EXPORT const QString & boolToOnOff(bool v)
Bool to on/off.
SWIFT_MISC_EXPORT QString removeSurroundingQuotes(const QString &in)
Remove surrounding quotes "foo" -> foo.
SWIFT_MISC_EXPORT double parseFraction(const QString &fraction, double failDefault=std::numeric_limits< double >::quiet_NaN())
Parse a fraction like 2/3.
SWIFT_MISC_EXPORT bool hasBalancedQuotes(const QString &in, char quote='"')
Has balanced quotes.
SWIFT_MISC_EXPORT QString dotToLocaleDecimalPoint(QString &input)
Replace dot '.' by locale decimal point.
SWIFT_MISC_EXPORT QString simplifyAccents(const QString &candidate)
Remove accents / diacritic marks from a string.
SWIFT_MISC_EXPORT bool stringCompare(const QString &c1, const QString &c2, Qt::CaseSensitivity cs)
String compare.
SWIFT_MISC_EXPORT QString inQuotes(const QString &in, bool ignoreEmpty=false)
Return string in quotes.
SWIFT_MISC_EXPORT QString removeSurroundingApostrophes(const QString &in)
Remove surrounding apostrophes 'foo' -> foo.
SWIFT_MISC_EXPORT QString joinStringSet(const QSet< QString > &set, const QString &separator)
Convert string to bool.
SWIFT_MISC_EXPORT const QString & boolToNullNotNull(bool isNull)
Bool isNull to null/no null.
SWIFT_MISC_EXPORT QStringList splitLines(const QString &s)
Split a string into multiple lines. Blank lines are skipped.
SWIFT_MISC_EXPORT QString removeComments(const QString &in, bool removeSlash, bool removeDoubleSlash)
Remove comments such as /** **/ or //.
SWIFT_MISC_EXPORT const QString & boolToEnabledDisabled(bool v)
Bool to enabled/disabled.
QStringList splitString(const QString &s, F predicate)
Split a string into multiple strings, using a predicate function to identify the split points.
SWIFT_MISC_EXPORT bool stringToBool(const QString &boolString)
Convert string to bool.
SWIFT_MISC_EXPORT bool containsAny(const QString &testString, const QStringList &any, Qt::CaseSensitivity cs)
Contains any string of the list?
SWIFT_MISC_EXPORT const QString & boolToTrueFalse(bool v)
Bool to true/false.
bool isDigitsOnlyString(const QString &testString)
String with digits only.
SWIFT_MISC_EXPORT QDateTime fromStringUtc(const QString &dateTimeString, const QString &format)
Same as QDateTime::fromString but QDateTime will be set to UTC.
SWIFT_MISC_EXPORT const QString & boolToYesNo(bool v)
Bool to yes/no.
SWIFT_MISC_EXPORT QDateTime parseDateTimeStringOptimized(const QString &dateTimeString)
Parse yyyyMMddHHmmsszzz strings optimized.
std::string toLower(std::string s)
String to lower case.