9 #include <QRegularExpression>
10 #include <QStringBuilder>
17 return removeChars(s, [](QChar c) {
return c == u
' ' || c == u
':' || c == u
'_' || c == u
'-' || c == u
'.'; });
22 return splitStringRefs(s, [](QChar c) {
return c ==
'\n' || c ==
'\r'; });
27 return splitString(s, [](QChar c) {
return c ==
'\n' || c ==
'\r'; });
33 for (
const QChar &c : s)
35 if (
const char latin = c.toLatin1())
37 if ((latin >=
'a' && latin <=
'z') || (latin >=
'A' && latin <=
'Z') ||
38 (latin >=
'0' && latin <=
'9') || allow.contains(latin))
40 result += c.toLatin1();
45 if (latin < 0x10) { result +=
'0'; }
46 result += QByteArray::number(
static_cast<int>(latin), 16);
53 const ushort unicode = c.unicode();
54 if (unicode < 0x0010) { result +=
'0'; }
55 if (unicode < 0x0100) { result +=
'0'; }
56 if (unicode < 0x1000) { result +=
'0'; }
57 result += QByteArray::number(unicode, 16);
66 for (
int i = 0; i < ba.size(); ++i)
71 Q_ASSERT(i < ba.size());
75 Q_ASSERT(i < ba.size());
76 result += QChar(ba.mid(i, 4).toInt(
nullptr, 16));
81 result +=
static_cast<char>(ba.mid(i, 2).toInt(
nullptr, 16));
85 else { result += ba[i]; }
92 static const QString on(
"on");
93 static const QString off(
"off");
99 static const QString yes(
"yes");
100 static const QString no(
"no");
106 static const QString t(
"true");
107 static const QString f(
"false");
113 static const QString e(
"enabled");
114 static const QString d(
"disabled");
120 static const QString n(
"null");
121 static const QString nn(
"not null");
122 return isNull ? n : nn;
127 QString s(
string.trimmed().
toLower());
128 if (s.isEmpty()) {
return false; }
131 const QChar c = s.at(0);
132 if (c ==
'1' || c ==
't' || c ==
'y' || c ==
'x') {
return true; }
133 if (c ==
'0' || c ==
'f' || c ==
'n' || c ==
'_') {
return false; }
135 if (c ==
'e') {
return true; }
136 if (c ==
'd') {
return false; }
139 if (s ==
"on") {
return true; }
146 if (cs == Qt::CaseInsensitive)
150 else if (str1 == str2) {
return 100; }
153 if (str1.isEmpty() || str2.isEmpty()) {
return 0; }
156 const QString aStr = str1.length() >= str2.length() ? str1 : str2;
157 const QString bStr = str1.length() >= str2.length() ? str2 : str1;
160 const double s1 = aStr.length();
161 const double s2 = bStr.length();
162 if (aStr.endsWith(bStr, cs)) {
return qRound(s1 / s2 * 100); }
163 if (aStr.startsWith(bStr, cs)) {
return qRound(s1 / s2 * 100); }
166 if (aStr.contains(bStr, cs)) {
return qRound(s1 / s2 * 100); }
170 for (
int p = 0; p < aStr.length(); p++)
172 if (p < bStr.length() && aStr[p] == bStr[p])
179 const int after = p + 1;
180 if (after < bStr.length() && aStr[p] == bStr[after])
187 const int before = p - 1;
188 if (before >= 0 && before < bStr.length() && aStr[p] == bStr[before])
194 return qRound(points / s1 * 100);
197 QString
intToHex(
int value,
int digits)
199 QString hex(QString::number(value, 16).toUpper());
200 int l = hex.length();
201 if (l >= digits) {
return hex.right(digits); }
203 return QString(d,
'0') + hex;
208 const QString s(candidate.trimmed().toUpper());
209 if (s.isEmpty()) {
return QString(); }
210 return s.contains(
' ') ? s.left(s.indexOf(
' ')) : s;
213 QStringList simpleTextCodecNamesImpl()
216 for (
const QByteArray &ba : QTextCodec::availableCodecs())
218 const QString c(QString::fromLocal8Bit(ba));
224 QStringList mibTextCodecNamesImpl()
227 for (
int mib : QTextCodec::availableMibs())
229 const QByteArray ba(QTextCodec::codecForMib(mib)->name());
230 const QString c(QString::fromLocal8Bit(ba));
238 static const QStringList simple(simpleTextCodecNamesImpl());
239 static const QStringList mib(mibTextCodecNamesImpl());
240 if (simpleNames && mibNames)
242 QStringList s(simple);
246 if (simpleNames) {
return simple; }
247 if (mibNames) {
return mib; }
248 return QStringList();
256 static const QString diacriticLetters =
257 QString::fromUtf8(
"ŠŒŽšœžŸ¥µÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýÿ");
258 static const QStringList noDiacriticLetters(
259 {
"S",
"OE",
"Z",
"s",
"oe",
"z",
"Y",
"Y",
"u",
"A",
"A",
"A",
"A",
"A",
"A",
"AE",
"C",
"E",
260 "E",
"E",
"E",
"I",
"I",
"I",
"I",
"D",
"N",
"O",
"O",
"O",
"O",
"O",
"O",
"U",
"U",
"U",
261 "U",
"Y",
"s",
"a",
"a",
"a",
"a",
"a",
"a",
"ae",
"c",
"e",
"e",
"e",
"e",
"i",
"i",
"i",
262 "i",
"o",
"n",
"o",
"o",
"o",
"o",
"o",
"o",
"u",
"u",
"u",
"u",
"y",
"y" });
265 for (
int i = 0; i < candidate.length(); i++)
267 const QChar c = candidate[i];
268 int dIndex = diacriticLetters.indexOf(c);
269 if (dIndex < 0) { output.append(c); }
272 const QString replacement = noDiacriticLetters[dIndex];
273 output.append(replacement);
284 for (
const QChar &c : s)
286 if (c.decompositionTag() == QChar::NoDecomposition) { result.push_back(c); }
289 for (
const QChar &dc : c.decomposition())
291 if (!dc.isMark()) { result.push_back(dc); }
300 return c1.length() == c2.length() && c1.startsWith(c2, Qt::CaseInsensitive);
305 return removeChars(name.toUpper(), [](QChar c) { return !c.isUpper(); });
308 QDateTime
fromStringUtc(
const QString &dateTimeString,
const QString &format)
310 if (dateTimeString.isEmpty() || format.isEmpty()) {
return QDateTime(); }
311 QDateTime dt = QDateTime::fromString(dateTimeString, format);
312 if (!dt.isValid()) {
return dt; }
313 dt.setOffsetFromUtc(0);
317 QDateTime
fromStringUtc(
const QString &dateTimeString, Qt::DateFormat format)
319 if (dateTimeString.isEmpty()) {
return QDateTime(); }
320 QDateTime dt = QDateTime::fromString(dateTimeString, format);
321 if (!dt.isValid()) {
return dt; }
322 dt.setOffsetFromUtc(0);
326 QDateTime
fromStringUtc(
const QString &dateTimeString,
const QLocale &locale, QLocale::FormatType format)
328 if (dateTimeString.isEmpty()) {
return QDateTime(); }
329 QDateTime dt = locale.toDateTime(dateTimeString, format);
330 if (!dt.isValid()) {
return dt; }
331 dt.setOffsetFromUtc(0);
337 if (dateTimeString.isEmpty()) {
return QDateTime(); }
341 if (dateTimeString.length() == 17) {
return fromStringUtc(dateTimeString,
"yyyyMMddHHmmsszzz"); }
342 if (dateTimeString.length() == 14) {
return fromStringUtc(dateTimeString,
"yyyyMMddHHmmss"); }
343 if (dateTimeString.length() == 12) {
return fromStringUtc(dateTimeString,
"yyyyMMddHHmm"); }
344 if (dateTimeString.length() == 8) {
return fromStringUtc(dateTimeString,
"yyyyMMdd"); }
356 QDateTime ts =
fromStringUtc(dateTimeString, Qt::ISODateWithMs);
357 if (ts.isValid())
return ts;
360 if (ts.isValid())
return ts;
363 if (ts.isValid())
return ts;
365 ts =
fromStringUtc(dateTimeString, QLocale(), QLocale::LongFormat);
366 if (ts.isValid())
return ts;
368 ts =
fromStringUtc(dateTimeString, QLocale(), QLocale::ShortFormat);
369 if (ts.isValid())
return ts;
378 if (dateTimeString.length() < 8) {
return QDateTime(); }
382 int year(QStringView { dateTimeString }.left(4).toInt());
383 int month(QStringView { dateTimeString }.mid(4, 2).toInt());
384 int day(QStringView { dateTimeString }.mid(6, 2).toInt());
386 date.setDate(year, month, day);
388 dt.setOffsetFromUtc(0);
390 if (dateTimeString.length() < 12) {
return dt; }
393 const int hour(QStringView { dateTimeString }.mid(8, 2).toInt());
394 const int minute(QStringView { dateTimeString }.mid(10, 2).toInt());
395 const int second(dateTimeString.length() < 14 ? 0 : QStringView { dateTimeString }.mid(12, 2).toInt());
396 const int ms(dateTimeString.length() < 17 ? 0 : QStringView { dateTimeString }.right(3).toInt());
398 t.setHMS(hour, minute, second, ms);
403 QString
dotToLocaleDecimalPoint(QString &input) {
return input.replace(
'.', QLocale::system().decimalPoint()); }
408 return copy.replace(
'.', QLocale::system().decimalPoint());
411 bool stringCompare(
const QString &c1,
const QString &c2, Qt::CaseSensitivity cs)
413 if (cs == Qt::CaseSensitive) {
return c1 == c2; }
419 if (in.isEmpty()) {
return ignoreEmpty ? QString() : QStringLiteral(
"''"); }
420 return u
'\'' % in % u
'\'';
423 QString
inQuotes(
const QString &in,
bool ignoreEmpty)
425 if (in.isEmpty()) {
return ignoreEmpty ? QString() : QStringLiteral(
"\"\""); }
426 return u
'"' % in % u
'"';
431 if (question.endsWith(
"?")) {
return question; }
432 return question % u
'?';
435 int nthIndexOf(
const QString &
string, QChar ch,
int nth, Qt::CaseSensitivity cs)
437 if (nth < 1 ||
string.isEmpty() || nth >
string.length()) {
return -1; }
441 for (
int t = 0; t < nth; ++t)
443 ci =
string.indexOf(ch, from, cs);
444 if (ci < 0) {
return -1; }
446 if (from >=
string.length()) {
return -1; }
451 QString
joinStringSet(
const QSet<QString> &set,
const QString &separator)
453 if (set.isEmpty()) {
return {}; }
454 if (set.size() == 1) {
return *set.begin(); }
455 return set.values().join(separator);
462 for (
const QStringRef &l : lines)
464 if (l.isEmpty()) {
continue; }
465 const int i = l.indexOf(
"=");
466 if (i < 0 || i >= l.length() + 1) {
continue; }
468 const QString key = l.left(i).trimmed().toString();
469 const QString value = l.mid(i + 1).toString();
470 if (value.isEmpty()) {
continue; }
471 map.insert(key, value);
478 if (in.size() < 2) {
return in; }
479 if (in.startsWith(
"'") && in.endsWith(
"'")) {
return in.mid(1, in.length() - 2); }
485 if (in.size() < 2) {
return in; }
486 if (in.startsWith(
"\"") && in.endsWith(
"\"")) {
return in.mid(1, in.length() - 2); }
490 QString
removeComments(
const QString &in,
bool removeSlashStar,
bool removeDoubleSlash)
494 thread_local
const QRegularExpression re1(
"\\/\\*(.|\\n)*?\\*\\/");
495 if (removeSlashStar) { copy.remove(re1); }
497 thread_local
const QRegularExpression re2(
"\\/\\/.*");
498 if (removeDoubleSlash) { copy.remove(re2); }
509 bool containsAny(
const QString &testString,
const QStringList &any, Qt::CaseSensitivity cs)
511 if (testString.isEmpty() || any.isEmpty()) {
return false; }
512 for (
const QString &a : any)
514 if (testString.contains(a, cs)) {
return true; }
521 if (in.isEmpty()) {
return true; }
522 const int c = in.count(quote);
526 double parseFraction(
const QString &fraction,
double failDefault)
528 if (fraction.isEmpty()) {
return failDefault; }
531 double r = failDefault;
532 if (fraction.contains(
'/'))
534 const QStringList parts = fraction.split(
'/');
535 if (parts.size() != 2) {
return failDefault; }
536 const double c = parts.front().trimmed().toDouble(&ok);
537 if (!ok) {
return failDefault; }
539 const double d = parts.last().trimmed().toDouble(&ok);
540 if (!ok) {
return failDefault; }
541 if (qFuzzyCompare(0.0, d)) {
return failDefault; }
546 r = fraction.trimmed().toDouble(&ok);
547 if (!ok) {
return failDefault; }
554 QString n = number.trimmed();
555 if (n.isEmpty()) {
return QString(); }
557 int dp = n.indexOf(
'.');
558 if (dp < 0) { dp = n.indexOf(
','); }
561 while (dp >= 0 && !n.isEmpty())
563 const QChar l = n.at(n.size() - 1);
569 else if (l ==
'.' || l ==
',') { n.chop(1); }
573 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 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 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 int nthIndexOf(const QString &string, QChar ch, int nth=1, Qt::CaseSensitivity cs=Qt::CaseInsensitive)
nth index of ch
SWIFT_MISC_EXPORT bool caseInsensitiveStringCompare(const QString &c1, const QString &c2)
Case insensitive string compare.
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 QStringList textCodecNames(bool simpleNames, bool mibNames)
Strip a designator from a combined string.
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.
QList< QStringRef > splitStringRefs(const QString &s, F predicate)
Split a string into multiple strings, using a predicate function to identify the split points.
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 & defaultIfEmpty(const QString &candidate, const QString &defaultIfEmpty)
Default string if string is empty.
SWIFT_MISC_EXPORT const QString & boolToYesNo(bool v)
Bool to yes/no.
SWIFT_MISC_EXPORT QDateTime parseDateTimeStringOptimized(const QString &dateTimeString)
Parse yyyyMMddHHmmsszzz strings optimized.
SWIFT_MISC_EXPORT QList< QStringRef > splitLinesRefs(const QString &s)
Split a string into multiple lines. Blank lines are skipped.
std::string toLower(std::string s)
String to lower case.