11 #include "LonLatParser_p.h"
13 #include "GeoDataCoordinates.h"
15 #include "MarbleDebug.h"
18 #include <QRegularExpression>
25 LonLatParser::LonLatParser()
28 , m_north(QStringLiteral(
"n"))
29 , m_east( QStringLiteral(
"e"))
30 , m_south(QStringLiteral(
"s"))
31 , m_west( QStringLiteral(
"w"))
32 , m_decimalPointExp(createDecimalPointExp())
37 void LonLatParser::initAll()
40 if (! m_dirCapExp.isEmpty()) {
45 const QString separator = QStringLiteral(
"|");
48 getLocaleList(m_northLocale, GeoDataCoordinates::tr(
"*",
"North direction terms"),
49 placeholder, separator);
51 getLocaleList(m_eastLocale, GeoDataCoordinates::tr(
"*",
"East direction terms"),
52 placeholder, separator);
54 getLocaleList(m_southLocale, GeoDataCoordinates::tr(
"*",
"South direction terms"),
55 placeholder, separator);
57 getLocaleList(m_westLocale, GeoDataCoordinates::tr(
"*",
"West direction terms"),
58 placeholder, separator);
62 << m_north << m_east << m_south << m_west;
63 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
69 dirs += m_northLocale.toSet();
70 dirs += m_eastLocale.toSet();
71 dirs += m_southLocale.toSet();
72 dirs += m_westLocale.toSet();
95 getLocaleList(m_degreeLocale, GeoDataCoordinates::tr(
"*",
"Degree symbol terms"),
96 placeholder, separator);
98 getLocaleList(m_minutesLocale, GeoDataCoordinates::tr(
"*",
"Minutes symbol terms"),
99 placeholder, separator);
101 getLocaleList(m_secondsLocale, GeoDataCoordinates::tr(
"*",
"Seconds symbol terms"),
102 placeholder, separator);
114 m_degreeExp = QStringLiteral(u
"\u00B0|\u00BA");
115 for(
const QString& symbol: m_degreeLocale) {
118 m_minutesExp = QStringLiteral(u
"'|\u2032|\u00B4|\u20C2|\u2019");
119 for(
const QString& symbol: m_minutesLocale) {
122 m_secondsExp = QStringLiteral(u
"\"|\u2033|\u201D|''|\u2032\u2032|\u00B4\u00B4|\u20C2\u20C2|\u2019\u2019");
123 for(
const QString& symbol: m_secondsLocale) {
128 bool LonLatParser::parse(
const QString&
string)
134 const QString numberCapExp = QStringLiteral(
"\\A(?:") +
135 QStringLiteral(
"([-+]?\\d{1,3}%1?\\d*(?:[eE][+-]?\\d+)?)(?:,|;|\\s)\\s*").
arg(m_decimalPointExp) +
136 QStringLiteral(
"([-+]?\\d{1,3}%1?\\d*(?:[eE][+-]?\\d+)?)").
arg(m_decimalPointExp) +
137 QStringLiteral(
")\\z");
141 if (
match.hasMatch()) {
142 m_lon = parseDouble(
match.captured(2));
143 m_lat = parseDouble(
match.captured(1));
151 if (tryMatchFromD(input, PostfixDir)) {
155 if (tryMatchFromD(input, PrefixDir)) {
159 if (tryMatchFromDms(input, PostfixDir)) {
163 if (tryMatchFromDms(input, PrefixDir)) {
167 if (tryMatchFromDm(input, PostfixDir)) {
171 if (tryMatchFromDm(input, PrefixDir)) {
179 bool LonLatParser::tryMatchFromDms(
const QString& input, DirPosition dirPosition)
182 const QString postfixCapExp = QStringLiteral(
"\\A(?:") +
183 QStringLiteral(
"([-+]?)(\\d{1,3})(?:%3|\\s)\\s*(\\d{1,2})(?:%4|\\s)\\s*") +
184 QStringLiteral(
"(\\d{1,2}%1?\\d*)(?:%5)?\\s*%2[,;]?\\s*") +
185 QStringLiteral(
"([-+]?)(\\d{1,3})(?:%3|\\s)\\s*(\\d{1,2})(?:%4|\\s)\\s*") +
186 QStringLiteral(
"(\\d{1,2}%1?\\d*)(?:%5)?\\s*%2") +
187 QStringLiteral(
")\\z");
190 const QString prefixCapExp = QStringLiteral(
"\\A(?:") +
191 QStringLiteral(
"%2\\s*([-+]?)(\\d{1,3})(?:%3|\\s)\\s*(\\d{1,2})(?:%4|\\s)\\s*") +
192 QStringLiteral(
"(\\d{1,2}%1?\\d*)(?:%5)?\\s*(?:,|;|\\s)\\s*") +
193 QStringLiteral(
"%2\\s*([-+]?)(\\d{1,3})(?:%3|\\s)\\s*(\\d{1,2})(?:%4|\\s)\\s*") +
194 QStringLiteral(
"(\\d{1,2}%1?\\d*)(?:%5)?") +
195 QStringLiteral(
")\\z");
197 const QString &expTemplate = (dirPosition == PostfixDir) ? postfixCapExp
200 const QString numberCapExp = expTemplate.
arg(m_decimalPointExp, m_dirCapExp,
201 m_degreeExp, m_minutesExp, m_secondsExp);
205 if (!
match.hasMatch()) {
210 bool isLonDirPosHemisphere;
211 bool isLatDirPosHemisphere;
212 const QString dir1 =
match.captured(dirPosition == PostfixDir ? 5 : 1);
213 const QString dir2 =
match.captured(dirPosition == PostfixDir ? 10 : 6);
214 if (!isCorrectDirections(dir1, dir2, isDir1LonDir,
215 isLonDirPosHemisphere, isLatDirPosHemisphere)) {
219 const int valueStartIndex1 = (dirPosition == PostfixDir ? 1 : 2);
220 const int valueStartIndex2 = (dirPosition == PostfixDir ? 6 : 7);
221 m_lon = degreeValueFromDMS(match, isDir1LonDir ? valueStartIndex1 : valueStartIndex2,
222 isLonDirPosHemisphere);
223 m_lat = degreeValueFromDMS(match, isDir1LonDir ? valueStartIndex2 : valueStartIndex1,
224 isLatDirPosHemisphere);
230 bool LonLatParser::tryMatchFromDm(
const QString& input, DirPosition dirPosition)
233 const QString postfixCapExp = QStringLiteral(
"\\A(?:") +
234 QStringLiteral(
"([-+]?)(\\d{1,3})(?:%3|\\s)\\s*(\\d{1,2}%1?\\d*)(?:%4)?\\s*%2[,;]?\\s*") +
235 QStringLiteral(
"([-+]?)(\\d{1,3})(?:%3|\\s)\\s*(\\d{1,2}%1?\\d*)(?:%4)?\\s*%2") +
236 QStringLiteral(
")\\z");
239 const QString prefixCapExp = QStringLiteral(
"\\A(?:") +
240 QStringLiteral(
"%2\\s*([-+]?)(\\d{1,3})(?:%3|\\s)\\s*(\\d{1,2}%1?\\d*)(?:%4)?\\s*(?:,|;|\\s)\\s*") +
241 QStringLiteral(
"%2\\s*([-+]?)(\\d{1,3})(?:%3|\\s)\\s*(\\d{1,2}%1?\\d*)(?:%4)?") +
242 QStringLiteral(
")\\z");
244 const QString& expTemplate = (dirPosition == PostfixDir) ? postfixCapExp
247 const QString numberCapExp = expTemplate.
arg(m_decimalPointExp, m_dirCapExp,
248 m_degreeExp, m_minutesExp);
251 if (!
match.hasMatch()) {
256 bool isLonDirPosHemisphere;
257 bool isLatDirPosHemisphere;
258 const QString dir1 =
match.captured(dirPosition == PostfixDir ? 4 : 1);
259 const QString dir2 =
match.captured(dirPosition == PostfixDir ? 8 : 5);
260 if (!isCorrectDirections(dir1, dir2, isDir1LonDir,
261 isLonDirPosHemisphere, isLatDirPosHemisphere)) {
265 const int valueStartIndex1 = (dirPosition == PostfixDir ? 1 : 2);
266 const int valueStartIndex2 = (dirPosition == PostfixDir ? 5 : 6);
267 m_lon = degreeValueFromDM(match, isDir1LonDir ? valueStartIndex1 : valueStartIndex2,
268 isLonDirPosHemisphere);
269 m_lat = degreeValueFromDM(match, isDir1LonDir ? valueStartIndex2 : valueStartIndex1,
270 isLatDirPosHemisphere);
276 bool LonLatParser::tryMatchFromD(
const QString& input, DirPosition dirPosition)
279 const QString postfixCapExp = QStringLiteral(
"\\A(?:") +
280 QStringLiteral(
"([-+]?\\d{1,3}%1?\\d*)(?:%3)?(?:\\s*)%2(?:,|;|\\s)\\s*") +
281 QStringLiteral(
"([-+]?\\d{1,3}%1?\\d*)(?:%3)?(?:\\s*)%2") +
282 QStringLiteral(
")\\z");
285 const QString prefixCapExp = QStringLiteral(
"\\A(?:") +
286 QStringLiteral(
"%2\\s*([-+]?\\d{1,3}%1?\\d*)(?:%3)?\\s*(?:,|;|\\s)\\s*") +
287 QStringLiteral(
"%2\\s*([-+]?\\d{1,3}%1?\\d*)(?:%3)?") +
288 QStringLiteral(
")\\z");
290 const QString& expTemplate = (dirPosition == PostfixDir) ? postfixCapExp
293 const QString numberCapExp = expTemplate.
arg(m_decimalPointExp, m_dirCapExp, m_degreeExp);
297 if (!
match.hasMatch()) {
304 bool isLonDirPosHemisphere;
305 bool isLatDirPosHemisphere;
306 const QString dir1 =
match.captured(dirPosition == PostfixDir ? 2 : 1);
307 const QString dir2 =
match.captured(dirPosition == PostfixDir ? 4 : 3);
308 if (!isCorrectDirections(dir1, dir2, isDir1LonDir,
309 isLonDirPosHemisphere, isLatDirPosHemisphere)) {
313 const int valueStartIndex1 = (dirPosition == PostfixDir ? 1 : 2);
314 const int valueStartIndex2 = (dirPosition == PostfixDir ? 3 : 4);
315 m_lon = degreeValueFromD(match, isDir1LonDir ? valueStartIndex1 : valueStartIndex2,
316 isLonDirPosHemisphere);
317 m_lat = degreeValueFromD(match, isDir1LonDir ? valueStartIndex2 : valueStartIndex1,
318 isLatDirPosHemisphere);
323 double LonLatParser::parseDouble(
const QString& input)
333 QString LonLatParser::createDecimalPointExp()
337 return (decimalPoint ==
QLatin1Char(
'.')) ? QStringLiteral(
"\\.") :
341 void LonLatParser::getLocaleList(
QStringList& localeList,
const QString& localeListString,
345 if (lowerLocaleListString != placeholder) {
352 return (directions.
contains(input));
355 bool LonLatParser::isDirection(
const QString& input,
const QString& direction)
357 return (input == direction);
360 bool LonLatParser::isOneOfDirections(
const QString& input,
362 const QString& secondDirection,
363 bool& isFirstDirection)
365 isFirstDirection = isDirection(input, firstDirection);
366 return isFirstDirection || isDirection(input, secondDirection);
369 bool LonLatParser::isOneOfDirections(
const QString& input,
372 bool& isFirstDirection)
374 isFirstDirection = isDirection(input, firstDirections);
375 return isFirstDirection || isDirection(input, secondDirections);
379 bool LonLatParser::isLocaleLonDirection(
const QString& input,
380 bool& isDirPosHemisphere)
const
382 return isOneOfDirections(input, m_eastLocale, m_westLocale, isDirPosHemisphere);
385 bool LonLatParser::isLocaleLatDirection(
const QString& input,
386 bool& isDirPosHemisphere)
const
388 return isOneOfDirections(input, m_northLocale, m_southLocale, isDirPosHemisphere);
391 bool LonLatParser::isLonDirection(
const QString& input,
392 bool& isDirPosHemisphere)
const
394 return isOneOfDirections(input, m_east, m_west, isDirPosHemisphere);
397 bool LonLatParser::isLatDirection(
const QString& input,
398 bool& isDirPosHemisphere)
const
400 return isOneOfDirections(input, m_north, m_south, isDirPosHemisphere);
409 const qreal seconds = parseDouble(regexMatch.
captured(c));
411 qreal result = degree + (minutes * MIN2HOUR) + (seconds * SEC2HOUR);
413 if (isNegativeValue) {
416 if (! isPosHemisphere) {
427 const qreal minutes = parseDouble(regexMatch.
captured(c));
429 qreal result = degree + (minutes * MIN2HOUR);
431 if (isNegativeValue) {
434 if (! isPosHemisphere) {
443 qreal result = parseDouble(regexMatch.
captured(c));
445 if (! isPosHemisphere) {
452 bool LonLatParser::isCorrectDirections(
const QString& dir1,
const QString& dir2,
454 bool& isLonDirPosHemisphere,
455 bool& isLatDirPosHemisphere)
const
458 isDir1LonDir = isLocaleLonDirection(dir1, isLonDirPosHemisphere);
459 const bool resultLocale = isDir1LonDir ?
460 isLocaleLatDirection(dir2, isLatDirPosHemisphere) :
461 (isLocaleLatDirection(dir1, isLatDirPosHemisphere) &&
462 isLocaleLonDirection(dir2, isLonDirPosHemisphere));
469 isDir1LonDir = isLonDirection(dir1, isLonDirPosHemisphere);
470 return isDir1LonDir ?
471 isLatDirection(dir2, isLatDirPosHemisphere) :
472 (isLatDirection(dir1, isLatDirPosHemisphere) &&
473 isLonDirection(dir2, isLonDirPosHemisphere));