9#include <QRegularExpression>
10#include <QRegularExpressionMatch>
30using namespace swift::misc::physical_quantities;
31using namespace swift::misc::aviation;
33namespace swift::misc::weather
41 class IMetarDecoderPart
45 virtual ~IMetarDecoderPart() =
default;
48 virtual QString getDecoderType()
const = 0;
52 virtual const QRegularExpression &getRegExp()
const = 0;
54 virtual bool isRepeatable()
const {
return false; }
55 virtual bool validateAndSet(
const QRegularExpressionMatch &match, CMetar &metar)
const = 0;
56 virtual bool isMandatory()
const = 0;
60 bool parse(QString &metarString, CMetar &metar)
63 const QRegularExpression re(getRegExp());
64 Q_ASSERT(re.isValid());
70 QRegularExpressionMatch match = re.match(metarString);
74 if (!validateAndSet(match, metar))
80 metarString.
replace(re, QString());
93 while (isRepeatable());
97 CLogMessage(
static_cast<CMetarDecoder *
>(
nullptr)).debug()
98 <<
"Failed to match" << getDecoderType() <<
"in remaining METAR:" << metarString;
105 class CMetarDecoderReportType :
public IMetarDecoderPart
108 QString getDecoderType()
const override {
return "ReportType"; }
111 const QRegularExpression &getRegExp()
const override
113 static const QRegularExpression re(QStringLiteral(
"^(?<reporttype>METAR|SPECI)? "));
117 bool validateAndSet(
const QRegularExpressionMatch &match, CMetar &metar)
const override
119 QString reportTypeAsString = match.
captured(
"reporttype");
120 if (reportTypeAsString.
isEmpty() || !getReportTypeHash().contains(reportTypeAsString))
125 metar.setReportType(getReportTypeHash().value(reportTypeAsString));
129 bool isMandatory()
const override {
return false; }
132 static const QHash<QString, CMetar::ReportType> &getReportTypeHash()
134 static const QHash<QString, CMetar::ReportType> hash = { {
"METAR", CMetar::METAR },
135 {
"SPECI", CMetar::SPECI } };
140 class CMetarDecoderAirport :
public IMetarDecoderPart
143 QString getDecoderType()
const override {
return "Airport"; }
146 const QRegularExpression &getRegExp()
const override
148 static const QRegularExpression re(QStringLiteral(
"^(?<airport>\\w{4}) "));
152 bool validateAndSet(
const QRegularExpressionMatch &match, CMetar &metar)
const override
154 QString airportAsString = match.
captured(
"airport");
155 Q_ASSERT(!airportAsString.
isEmpty());
156 metar.setAirportIcaoCode(CAirportIcaoCode(airportAsString));
160 bool isMandatory()
const override {
return true; }
163 class CMetarDecoderDayTime :
public IMetarDecoderPart
166 QString getDecoderType()
const override {
return "DayTime"; }
169 const QRegularExpression &getRegExp()
const override
171 static const QRegularExpression re(QStringLiteral(
"^(?<day>\\d{2})(?<hour>\\d{2})(?<minute>\\d{2})Z "));
175 bool validateAndSet(
const QRegularExpressionMatch &match, CMetar &metar)
const override
181 if (!ok)
return false;
183 if (day < 1 || day > 31)
return false;
184 if (hour < 0 || hour > 23)
return false;
185 if (minute < 0 || minute > 59)
return false;
187 physical_quantities::CTime time(hour, minute, 0);
188 metar.setDayTime(day, time);
192 bool isMandatory()
const override {
return true; }
195 class CMetarDecoderStatus :
public IMetarDecoderPart
198 QString getDecoderType()
const override {
return "Status"; }
205 const QRegularExpression &getRegExp()
const override
207 static const QRegularExpression re(QStringLiteral(
"^([A-Z]+) "));
211 bool validateAndSet(
const QRegularExpressionMatch &match, CMetar &metar)
const override
215 metar.setAutomated(
true);
218 else if (match.
captured(1) ==
"NIL")
232 bool isMandatory()
const override {
return false; }
235 class CMetarDecoderWind :
public IMetarDecoderPart
238 QString getDecoderType()
const override {
return "Wind"; }
241 static const QHash<QString, CSpeedUnit> &getWindUnitHash()
243 static const QHash<QString, CSpeedUnit> hash = { {
"KT", CSpeedUnit::kts() },
244 {
"MPS", CSpeedUnit::m_s() },
245 {
"KPH", CSpeedUnit::km_h() },
246 {
"KMH", CSpeedUnit::km_h() } };
250 const QRegularExpression &getRegExp()
const override
252 static const QRegularExpression re(getRegExpImpl());
256 bool validateAndSet(
const QRegularExpressionMatch &match, CMetar &metar)
const override
259 QString directionAsString = match.
captured(
"direction");
260 if (directionAsString ==
"///")
return true;
262 bool directionVariable =
false;
263 if (directionAsString ==
"VRB")
265 directionVariable =
true;
269 direction = directionAsString.
toInt(&ok);
270 if (!ok)
return false;
273 QString speedAsString = match.
captured(
"speed");
274 if (speedAsString ==
"//")
return true;
275 int speed = speedAsString.
toInt(&ok);
276 if (!ok)
return false;
277 QString gustAsString = match.
captured(
"gustSpeed");
281 gustSpeed = gustAsString.
toInt(&ok);
282 if (!ok)
return false;
284 QString unitAsString = match.
captured(
"unit");
285 if (!getWindUnitHash().contains(unitAsString))
return false;
287 CWindLayer windLayer(CAltitude(0, CAltitude::AboveGround, CLengthUnit::ft()),
289 CSpeed(speed, getWindUnitHash().value(unitAsString)),
290 CSpeed(gustSpeed, getWindUnitHash().value(unitAsString)));
291 windLayer.setDirectionVariable(directionVariable);
292 metar.setWindLayer(windLayer);
296 bool isMandatory()
const override {
return false; }
299 QString getRegExpImpl()
const
302 const QString direction = QStringLiteral(
"(?<direction>\\d{3}|VRB|/{3})");
304 const QString speed = QStringLiteral(
"(?<speed>\\d{2,3}|/{2})");
306 const QString gustSpeed = QStringLiteral(
"(G(?<gustSpeed>\\d{2,3}))?");
308 const QString unit = QStringLiteral(
"(?<unit>") + QStringList(getWindUnitHash().keys()).join(
'|') +
")";
310 const QString regexp =
"^" + direction + speed + gustSpeed + unit +
" ?";
315 class CMetarDecoderVariationsWindDirection :
public IMetarDecoderPart
318 QString getDecoderType()
const override {
return "WindDirection"; }
321 const QRegularExpression &getRegExp()
const override
323 static const QRegularExpression re(getRegExpImpl());
327 bool validateAndSet(
const QRegularExpressionMatch &match, CMetar &metar)
const override
329 QString directionFromAsString = match.
captured(
"direction_from");
330 QString directionToAsString = match.
captured(
"direction_to");
332 int directionFrom = 0;
336 directionFrom = directionFromAsString.
toInt(&ok);
337 directionTo = directionToAsString.
toInt(&ok);
338 if (!ok)
return false;
340 auto windLayer = metar.getWindLayer();
342 metar.setWindLayer(windLayer);
346 bool isMandatory()
const override {
return false; }
349 static QString getRegExpImpl()
352 const QString directionFrom(
"(?<direction_from>\\d{3})V");
354 const QString directionTo(
"(?<direction_to>\\d{3})");
356 const QString regexp =
"^" + directionFrom + directionTo +
" ";
361 class CMetarDecoderVisibility :
public IMetarDecoderPart
364 QString getDecoderType()
const override {
return "Visibility"; }
367 static const QHash<QString, QString> &getCardinalDirections()
369 static const QHash<QString, QString> hash = {
370 {
"N",
"north" }, {
"NE",
"north-east" }, {
"E",
"east" }, {
"SE",
"south-east" },
371 {
"S",
"south" }, {
"SW",
"south-west" }, {
"W",
"west" }, {
"NW",
"north-west" },
376 const QRegularExpression &getRegExp()
const override
378 static const QRegularExpression re(getRegExpImpl());
382 bool validateAndSet(
const QRegularExpressionMatch &match, CMetar &metar)
const override
390 QString visibilityAsString = match.
captured(
"visibility");
391 if (visibilityAsString ==
"////")
return true;
393 double visibility = 0;
394 if (!visibilityAsString.
isEmpty())
396 visibility = visibilityAsString.
toDouble(&ok);
397 if (!ok)
return false;
398 metar.setVisibility(CLength(visibility, CLengthUnit::m()));
402 QString distanceAsString = match.
captured(
"distance");
403 if (!distanceAsString.
isEmpty())
405 visibility += distanceAsString.
toDouble(&ok);
406 if (!ok)
return false;
408 QString numeratorAsString = match.
captured(
"numerator");
409 QString denominatorAsString = match.
captured(
"denominator");
410 if (!numeratorAsString.
isEmpty() && !denominatorAsString.
isEmpty())
413 double numerator = numeratorAsString.
toDouble(&ok);
414 if (!ok)
return false;
416 double denominator = denominatorAsString.
toDouble(&ok);
417 if (!ok)
return false;
418 if (denominator < 1 || numerator < 1)
return false;
419 visibility += (numerator / denominator);
422 QString unitAsString = match.
captured(
"unit");
423 CLengthUnit unit = CLengthUnit::SM();
424 if (unitAsString ==
"KM") unit = CLengthUnit::km();
426 metar.setVisibility(CLength(visibility, unit));
431 bool isMandatory()
const override {
return false; }
434 QString getRegExpImpl()
const
437 const QString cavok = QStringLiteral(
"(?<cavok>CAVOK)");
443 const QString visibility_eu = QStringLiteral(
"(?<visibility>\\d{4}|/{4})(NDV)?") +
"(" +
444 QStringList(getCardinalDirections().keys()).join(
'|') +
")?";
451 const QString visibility_us =
452 QStringLiteral(
"(?<distance>\\d{0,2}) ?M?((?<numerator>\\d)/(?<denominator>\\d))?(?<unit>SM|KM)");
453 const QString regexp =
"^(" + cavok +
"|" + visibility_eu +
"|" + visibility_us +
") ";
458 class CMetarDecoderRunwayVisualRange :
public IMetarDecoderPart
461 QString getDecoderType()
const override {
return "RunwayVisualRange"; }
464 const QRegularExpression &getRegExp()
const override
467 static const QRegularExpression re(getRegExpImpl());
471 bool validateAndSet(
const QRegularExpressionMatch &match, CMetar &metar)
const override
473 QString runway = match.
captured(
"runway");
474 QString runwayVisibilityAsString = match.
captured(
"rwy_visibility");
475 Q_ASSERT(!runway.
isEmpty() && !runwayVisibilityAsString.
isEmpty());
478 double runwayVisibility = runwayVisibilityAsString.
toDouble(&ok);
479 if (!ok)
return false;
480 CLengthUnit lengthUnit = CLengthUnit::m();
481 if (match.
captured(
"unit") ==
"FT") lengthUnit = CLengthUnit::ft();
484 Q_UNUSED(runwayVisibility)
489 bool isMandatory()
const override {
return false; }
492 static QString getRegExpImpl()
501 const QString runway = QStringLiteral(
"R(?<runway>\\d{2}[LCR]*)");
503 const QString visibility = QStringLiteral(
"/[PM]?(?<rwy_visibility>\\d{4})");
505 static const QString variability = QStringLiteral(
"V?(?<variability>\\d{4})?");
507 const QString unit = QStringLiteral(
"(?<unit>FT)?");
509 const QString trend = QStringLiteral(
"/?(?<trend>[DNU])?");
510 const QString regexp =
"^" + runway + visibility + variability + unit + trend +
" ";
515 class CMetarDecoderPresentWeather :
public IMetarDecoderPart
518 QString getDecoderType()
const override {
return "PresentWeather"; }
521 static const QHash<QString, CPresentWeather::Intensity> &getIntensityHash()
523 static const QHash<QString, CPresentWeather::Intensity> hash = { {
"-", CPresentWeather::Light },
524 {
"+", CPresentWeather::Heavy },
525 {
"VC", CPresentWeather::InVincinity } };
529 static const QHash<QString, CPresentWeather::Descriptor> &getDescriptorHash()
531 static const QHash<QString, CPresentWeather::Descriptor> hash = {
532 {
"MI", CPresentWeather::Shallow }, {
"BC", CPresentWeather::Patches },
533 {
"PR", CPresentWeather::Partial }, {
"DR", CPresentWeather::Drifting },
534 {
"BL", CPresentWeather::Blowing }, {
"SH", CPresentWeather::Showers },
535 {
"TS", CPresentWeather::Thunderstorm }, {
"FR", CPresentWeather::Freezing },
540 static const QHash<QString, CPresentWeather::WeatherPhenomenon> &getWeatherPhenomenaHash()
542 static const QHash<QString, CPresentWeather::WeatherPhenomenon> hash = {
543 {
"DZ", CPresentWeather::Drizzle },
544 {
"RA", CPresentWeather::Rain },
545 {
"SN", CPresentWeather::Snow },
546 {
"SG", CPresentWeather::SnowGrains },
547 {
"IC", CPresentWeather::IceCrystals },
548 {
"PC", CPresentWeather::IcePellets },
549 {
"GR", CPresentWeather::Hail },
550 {
"GS", CPresentWeather::SnowPellets },
551 {
"UP", CPresentWeather::Unknown },
552 {
"BR", CPresentWeather::Mist },
553 {
"FG", CPresentWeather::Fog },
554 {
"FU", CPresentWeather::Smoke },
555 {
"VA", CPresentWeather::VolcanicAsh },
556 {
"DU", CPresentWeather::Dust },
557 {
"SA", CPresentWeather::Sand },
558 {
"HZ", CPresentWeather::Haze },
559 {
"PO", CPresentWeather::DustSandWhirls },
560 {
"SQ", CPresentWeather::Squalls },
561 {
"FC", CPresentWeather::TornadoOrWaterspout },
562 {
"FC", CPresentWeather::FunnelCloud },
563 {
"SS", CPresentWeather::Sandstorm },
564 {
"DS", CPresentWeather::Duststorm },
570 bool isRepeatable()
const override {
return true; }
572 const QRegularExpression &getRegExp()
const override
574 static const QRegularExpression re(getRegExpImpl());
578 bool validateAndSet(
const QRegularExpressionMatch &match, CMetar &metar)
const override
580 QString intensityAsString = match.
captured(
"intensity");
581 CPresentWeather::Intensity itensity = CPresentWeather::Moderate;
582 if (!intensityAsString.
isEmpty())
584 itensity = getIntensityHash().value(intensityAsString);
587 QString descriptorAsString = match.
captured(
"descriptor");
588 CPresentWeather::Descriptor descriptor = CPresentWeather::None;
589 if (!descriptorAsString.
isEmpty())
591 descriptor = getDescriptorHash().value(descriptorAsString);
594 int weatherPhenomena = 0;
595 QString wp1AsString = match.
captured(
"wp1");
598 weatherPhenomena |= getWeatherPhenomenaHash().value(wp1AsString);
601 QString wp2AsString = match.
captured(
"wp2");
604 weatherPhenomena |= getWeatherPhenomenaHash().value(wp2AsString);
607 CPresentWeather presentWeather(itensity, descriptor, weatherPhenomena);
608 metar.addPresentWeather(presentWeather);
612 bool isMandatory()
const override {
return false; }
615 QString getRegExpImpl()
const
623 const QString qualifier_intensity(
"(?<intensity>[-+]|VC)?");
625 const QString qualifier_descriptor =
626 "(?<descriptor>" + QStringList(getDescriptorHash().keys()).join(
'|') +
")?";
627 const QString weatherPhenomenaJoined = QStringList(getWeatherPhenomenaHash().keys()).join(
'|');
628 const QString weather_phenomina1 =
"(?<wp1>" + weatherPhenomenaJoined +
")?";
629 const QString weather_phenomina2 =
"(?<wp2>" + weatherPhenomenaJoined +
")?";
630 const QString weather_phenomina3 =
"(?<wp3>" + weatherPhenomenaJoined +
")?";
631 const QString weather_phenomina4 =
"(?<wp4>" + weatherPhenomenaJoined +
")?";
632 const QString regexp =
"^(" + qualifier_intensity + qualifier_descriptor + weather_phenomina1 +
633 weather_phenomina2 + weather_phenomina3 + weather_phenomina4 +
") ";
638 class CMetarDecoderCloud :
public IMetarDecoderPart
641 QString getDecoderType()
const override {
return "Cloud"; }
644 static const QStringList &getClearSkyTokens()
646 static const QStringList list = {
"SKC",
"NSC",
"CLR",
"NCD" };
650 static const QHash<QString, CCloudLayer::Coverage> &getCoverage()
652 static const QHash<QString, CCloudLayer::Coverage> hash = { {
"///", CCloudLayer::None },
653 {
"FEW", CCloudLayer::Few },
654 {
"SCT", CCloudLayer::Scattered },
655 {
"BKN", CCloudLayer::Broken },
656 {
"OVC", CCloudLayer::Overcast } };
660 bool isRepeatable()
const override {
return true; }
662 const QRegularExpression &getRegExp()
const override
664 static const QRegularExpression re(getRegExpImpl());
668 bool validateAndSet(
const QRegularExpressionMatch &match, CMetar &metar)
const override
670 QString noClouds = match.
captured(
"clear_sky");
673 metar.removeAllClouds();
677 QString coverageAsString = match.
captured(
"coverage");
678 QString baseAsString = match.
captured(
"base");
680 Q_ASSERT(getCoverage().contains(coverageAsString));
681 if (baseAsString ==
"///")
return true;
684 int base = baseAsString.
toInt(&ok);
687 if (!ok)
return false;
689 CCloudLayer cloudLayer(CAltitude(base, CAltitude::AboveGround, CLengthUnit::ft()), {},
690 getCoverage().value(coverageAsString));
691 metar.addCloudLayer(cloudLayer);
692 QString cb_tcu = match.
captured(
"cb_tcu");
699 bool isMandatory()
const override {
return false; }
702 QString getRegExpImpl()
const
705 const QString clearSky = QString(
"(?<clear_sky>") + getClearSkyTokens().join(
'|') + QString(
")");
707 const QString coverage =
708 QString(
"(?<coverage>") + QStringList(getCoverage().keys()).join(
'|') + QString(
")");
710 const QString base = QStringLiteral(
"(?<base>\\d{3}|///)");
712 const QString extra = QStringLiteral(
"(?<cb_tcu>CB|TCU|///)?");
714 const QString regexp = QString(
"^(") + clearSky +
'|' + coverage + base + extra + QString(
") ");
719 class CMetarDecoderVerticalVisibility :
public IMetarDecoderPart
722 QString getDecoderType()
const override {
return "VerticalVisibility"; }
725 const QRegularExpression &getRegExp()
const override
727 static const QRegularExpression re(getRegExpImpl());
731 bool validateAndSet(
const QRegularExpressionMatch & , CMetar & )
const override
737 bool isMandatory()
const override {
return false; }
740 static QString getRegExpImpl()
743 const QString verticalVisibility = QStringLiteral(
"VV(?<vertical_visibility>\\d{3}|///)");
744 const QString regexp =
"^" + verticalVisibility +
" ";
749 class CMetarDecoderTemperature :
public IMetarDecoderPart
752 QString getDecoderType()
const override {
return "Temperature"; }
755 const QRegularExpression &getRegExp()
const override
757 static const QRegularExpression re(getRegExpImpl());
761 bool validateAndSet(
const QRegularExpressionMatch &match, CMetar &metar)
const override
763 QString temperatureAsString = match.
captured(
"temperature");
764 if (temperatureAsString.
isEmpty())
return false;
765 QString dewPointAsString = match.
captured(
"dew_point");
766 if (dewPointAsString.
isEmpty())
return false;
768 if (temperatureAsString ==
"//" || dewPointAsString ==
"//")
return true;
770 bool temperatureNegative =
false;
773 temperatureNegative =
true;
774 temperatureAsString.
remove(
'M');
777 bool dewPointNegative =
false;
780 dewPointNegative =
true;
781 dewPointAsString.
remove(
'M');
784 int temperature = temperatureAsString.
toInt();
785 if (temperatureNegative)
789 metar.setTemperature(CTemperature(temperature, CTemperatureUnit::C()));
791 int dewPoint = dewPointAsString.
toInt();
792 if (dewPointNegative)
796 metar.setDewPoint(CTemperature(dewPoint, CTemperatureUnit::C()));
801 bool isMandatory()
const override {
return false; }
804 static QString getRegExpImpl()
807 const QString temperature = QStringLiteral(
"(?<temperature>M?\\d{2}|//)");
809 const QString separator =
"/";
811 const QString dewPoint = QStringLiteral(
"(?<dew_point>M?\\d{2}|//)");
813 const QString regexp =
"^" + temperature + separator + dewPoint +
" ?";
818 class CMetarDecoderPressure :
public IMetarDecoderPart
821 QString getDecoderType()
const override {
return "Pressure"; }
824 static const QHash<QString, CPressureUnit> &getPressureUnits()
826 static const QHash<QString, CPressureUnit> hash = { {
"Q", CPressureUnit::hPa() },
827 {
"A", CPressureUnit::inHg() } };
831 const QRegularExpression &getRegExp()
const override
833 static const QRegularExpression re(getRegExpImpl());
837 bool validateAndSet(
const QRegularExpressionMatch &match, CMetar &metar)
const override
839 QString unitAsString = match.
captured(
"unit");
840 QString pressureAsString = match.
captured(
"pressure");
841 QString qfeAsString = match.
captured(
"qfe");
845 if (pressureAsString ==
"////")
return true;
849 Q_ASSERT(getPressureUnits().contains(unitAsString));
851 double pressure = pressureAsString.
toDouble(&ok);
852 if (!ok)
return false;
853 CPressureUnit pressureUnit = getPressureUnits().value(unitAsString);
854 if (pressureUnit == CPressureUnit::inHg()) pressure /= 100;
855 metar.setAltimeter(CPressure(pressure, pressureUnit));
867 bool isMandatory()
const override {
return false; }
870 static QString getRegExpImpl()
874 const QString unit = QStringLiteral(
"((?<unit>Q|A)");
876 const QString pressure = QStringLiteral(
"(?<pressure>\\d{4}|////) ?)");
878 const QString qfe = QStringLiteral(
"(QFE (?<qfe>\\d+).\\d");
879 const QString regexp =
"^" + unit + pressure +
"|" + qfe +
" ?)";
884 class CMetarDecoderRecentWeather :
public IMetarDecoderPart
887 QString getDecoderType()
const override {
return "RecentWeather"; }
890 const QRegularExpression &getRegExp()
const override
892 static const QRegularExpression re(getRegExpImpl());
896 bool validateAndSet(
const QRegularExpressionMatch & , CMetar & )
const override
902 bool isMandatory()
const override {
return false; }
905 QString getRegExpImpl()
const
908 const QString qualifier_intensity(
"(?<intensity>[-+]|VC)?");
910 const QString qualifier_descriptor =
"(?<descriptor>" + m_descriptor.join(
'|') +
")?";
911 const QString weather_phenomina1 =
"(?<wp1>" + m_phenomina.join(
'|') +
")?";
912 const QString weather_phenomina2 =
"(?<wp2>" + m_phenomina.join(
'|') +
")?";
913 const QString weather_phenomina3 =
"(?<wp3>" + m_phenomina.join(
'|') +
")?";
914 const QString weather_phenomina4 =
"(?<wp4>" + m_phenomina.join(
'|') +
")?";
915 const QString regexp =
"^RE" + qualifier_intensity + qualifier_descriptor + weather_phenomina1 +
916 weather_phenomina2 + weather_phenomina3 + weather_phenomina4 +
" ";
920 const QStringList m_descriptor = QStringList {
"MI",
"BC",
"PR",
"DR",
"BL",
"SH",
"TS",
"FZ" };
921 const QStringList m_phenomina =
922 QStringList {
"DZ",
"RA",
"SN",
"SG",
"IC",
"PE",
"GR",
"GS",
"BR",
"FG",
"FU",
923 "VA",
"IC",
"DU",
"SA",
"HZ",
"PY",
"PO",
"SQ",
"FC",
"SS",
"DS" };
926 class CMetarDecoderWindShear :
public IMetarDecoderPart
929 QString getDecoderType()
const override {
return "WindShear"; }
932 const QRegularExpression &getRegExp()
const override
934 static const QRegularExpression re(getRegExpImpl());
938 bool validateAndSet(
const QRegularExpressionMatch &match, CMetar &metar)
const override
940 QString runwayAsString = match.
captured(
"runway");
944 Q_UNUSED(runwayAsString)
951 bool isMandatory()
const override {
return false; }
954 static QString getRegExpImpl()
957 const QString wsAllRwy = QStringLiteral(
"WS ALL RWY");
959 const QString runway = QStringLiteral(
"RW?Y?(?<runway>\\d{2}[LCR]*)");
960 const QString regexp =
"^WS (" + wsAllRwy +
"|" + runway +
") ";
972 QString metarStringCopy = metarString.
simplified();
974 for (
const auto &decoder : m_decoders)
976 if (!decoder->parse(metarStringCopy, metar))
978 const QString type = decoder->getDecoderType();
979 CLogMessage(
this).debug() <<
"Invalid METAR:" << metarString << type;
984 metar.setMessage(metarString);
988 void CMetarDecoder::allocateDecoders()
991 m_decoders.push_back(std::make_unique<CMetarDecoderReportType>());
992 m_decoders.push_back(std::make_unique<CMetarDecoderAirport>());
993 m_decoders.push_back(std::make_unique<CMetarDecoderDayTime>());
994 m_decoders.push_back(std::make_unique<CMetarDecoderStatus>());
995 m_decoders.push_back(std::make_unique<CMetarDecoderWind>());
996 m_decoders.push_back(std::make_unique<CMetarDecoderVariationsWindDirection>());
997 m_decoders.push_back(std::make_unique<CMetarDecoderVisibility>());
998 m_decoders.push_back(std::make_unique<CMetarDecoderRunwayVisualRange>());
999 m_decoders.push_back(std::make_unique<CMetarDecoderPresentWeather>());
1000 m_decoders.push_back(std::make_unique<CMetarDecoderCloud>());
1001 m_decoders.push_back(std::make_unique<CMetarDecoderVerticalVisibility>());
1002 m_decoders.push_back(std::make_unique<CMetarDecoderTemperature>());
1003 m_decoders.push_back(std::make_unique<CMetarDecoderPressure>());
1004 m_decoders.push_back(std::make_unique<CMetarDecoderRecentWeather>());
1005 m_decoders.push_back(std::make_unique<CMetarDecoderWindShear>());
static CAngleUnit deg()
Degrees.
QString captured(QAnyStringView name) const const
bool hasMatch() const const
bool isEmpty() const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QString simplified() const const
qsizetype size() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
double toDouble(bool *ok) const const
int toInt(bool *ok, int base) const const