Spencer
Spencer

Reputation: 642

c# regex match with string comparison (finding smallest value)

I am completely stumped on how to achieve this. Basically, I want to find the ceiling in a METAR report. The ceiling is the smallest broken or overcast layer.

I currently have this (which is not much by any means):

MatchCollection matches = Regex.Matches(modify, @"(BKN|OVC)([0-9]{3})");
foreach (Match match in matches)
{
    foreach (Capture capture in match.Captures)
    {
        // compare broken and overcast layers to find smallest value and set as the ceiling
        Console.WriteLine(capture.Value);
    }
}

Basically this searches the METAR string for BKN or OVC layers and spits them out. Take this METAR reading for example:

PANC 040553Z 17013G24KT 280V360 2SM FEW050 BKN019 BKN008 OVC005 14/M07 A2999 RMK AO2 SLP156 SH DSNT W-N T01390067 10167 20139 53002

The code I currently have will spit out BKN019, BKN008 and OVC005. What I need to do, is pick the smallest of these values (which, in this case, would be OVC005).

If someone can help me, I would greatly appreciate it.

Upvotes: 0

Views: 592

Answers (4)

ChaseMedallion
ChaseMedallion

Reputation: 21764

Try using capturing groups:

// (?<number> names the group that captures the number value
var matches = Regex.Matches(modify, @"(BKN|OVC)(?<number>[0-9]{3})");

// cast to IEnumerable<Match>()
var smallest = matches.Cast<Match>()
    // order by the parsed number group
    // Added `.Value` to make this work
    .OrderBy(m => int.Parse(m.Groups["number"].Value))
    // Select the string value
    .Select(m => m.Value)
    // take the first (the smallest)
    .FirstOrDefault();

if smallest is null then no matches found

Upvotes: 3

Bob Vale
Bob Vale

Reputation: 18474

Linq is your friend

remember using System.Linq

MatchCollection matches = Regex.Matches(modify, @"(BKN|OVC)([0-9]{3})");
var first = (
             from x in matches.OfType<Match>()
             orderby int.Parse(x.Groups[2].Value)
             select x.Value
            ).FirstOrDefault();

Upvotes: 0

Simon Belanger
Simon Belanger

Reputation: 14880

If I understand correctly, you want to take the whole capture for the smallest 2nd group.

matches.OfType<Match>()
       .Select(m => new { Capture = m.Groups[0], Number = Int32.Parse(m.Groups[2]) })
       .OrderBy(m =­> m.Number)
       .Select(m => m.Capture)
       .FirstOrDefault();

Upvotes: 1

Jashaszun
Jashaszun

Reputation: 9270

Basically what you want to do is keep track of the lowest layer found so far and then check for each regex match whether it's lower than before:

int lowestLayer = int.MaxValue;
MatchCollection matches = Regex.Matches(modify, @"(BKN|OVC)([0-9]{3})");
foreach (Match match in matches)
{
    foreach (Capture capture in match.Captures)
    {
        int layer = int.Parse(capture.Value.Substring(3));
        if (layer < lowestLayer)
            lowestLayer = layer;
        Console.WriteLine(capture.Value);
    }
}

Upvotes: 1

Related Questions