0

I want to extract the double from my string.

buff = "VA VV_CELL1 3.55"

When i use the following code

private void GetLine(string msg, string buff, double numb)
{
    comPort.WriteLine(msg); 
    Thread.Sleep(50);
    buff = comPort.ReadExisting();
    Thread.Sleep(50);
    MatchCollection matches = Regex.Matches(buff, @".*?([-]{0,1} *\d+.\d+)");
    List<double> doubles = new List<double>();
    foreach (Match match in matches)
    {
        string value = match.Groups[1].Value;
        value = value.Replace(" ", "");
        doubles.Add(double.Parse(value));
        Thread.Sleep(200);
        numb = doubles[0];                
    } 
}

This code work for my other strings but "CELL1" contains a number so i dont get the wanted value "3.55" any ideas?

4
  • I don't understand the goal of Thread.Sleep in your foreach loop Commented Dec 19, 2017 at 12:24
  • just test the value for any nonnumerical chars(excluding the decimal seperator) before parsing Commented Dec 19, 2017 at 12:26
  • You always want to extract the last number from a string? Commented Dec 19, 2017 at 12:28
  • I assume you want to capture both doubles and integers, otherwise you could write \d+\.\d+. You can capture a decimal preceded by whitespace with \s+\d+(\.\d+)?. If you want to capture only the last field, \s+\d+(\.\d+)?$ Commented Dec 19, 2017 at 12:33

3 Answers 3

6

Why you don't simply split this string and take the last part?

string numberPart = buff.Split().Last();
double num;
bool validNum = double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out num);

Another way is to use Substring and LastIndexOf(which fails if there is no space):

string numberPart = buff.Substring(buff.LastIndexOf(' ')).Trim();

To help on your comment:

I'd use a method that returns a double?(double that can be null):

double? GetNumber(string buff)
{
    string numberPart = buff.Split().Last();
    double num;
    bool validNum = double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out num);
    if (validNum)
        return num;
    else
        return null;
}

Now you can use the method and you even know whether the number could be parsed successfully or not:

double? result = GetNumber("VA VV_CELL1");
bool wasValid = result.HasValue;
if(wasValid)
{
   double value = result.Value;
}
Sign up to request clarification or add additional context in comments.

8 Comments

Splitting generates a lot of temporary strings that can be very expensive in when parsing a large number of records. If the record is fixed length though, the lines short or the number of records small, regular expressions can be overkill
@PanagiotisKanavos: In OP's sample it generates 3 temp strings. I dont think this is too much overhead. However, you can also use buff.Substring(buff.LastIndexOf(' ')).Trim(). Normally regex is much more expensive
Thx mate it helped a lot!
@TimSchmelter ` private void GetGet(string msg, string buff, double var) { comPort.WriteLine(msg); Thread.Sleep(200); buff = comPort.ReadLine(); Thread.Sleep(200); string numberPart = buff.Split().Last(); double num; bool validNum = double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out num); var = num; } ` when i call my method GetGet("VA VV_CELL1", buff1, var1); var1 is 0, why?
@xBehemoth: you either have to return num or make the parameter var ref. I'd prefer a method double GetValue(string msg, string buff, double var){ ... return num;}
|
1

Try, this regex expression : \s+\d+(.)?\d+

Comments

0

I assume you want to capture both doubles and integers, otherwise you could write \d+\.\d+. This :

Regex.Matches("VA VV_CELL1 3.55",@"\d+\.\d+")[0]

Returns 3.55 but can't capture 355.

You can capture an integer or decimal preceded by whitespace with \s+\d+(\.\d+)?.

Regex.Matches("VA VV_CELL1 3.55",@"\s+\d+(\.\d+)?")[0]

Returns 3.55 while

Regex.Matches("VA VV_CELL1 355",@"\s+\d+(\.\d+)?")[0]

Returns 355

If you want to capture only the last field you can use \s+\d+(\.\d+)?$,eg:

Regex.Matches("VA VV_CELL1 3.54 3.55",@"\s+\d+(\.\d+)?$")[0]

Returns 3.55

You don't need to trim whitespace because double.Parse ignores it. You can change the pattern to capture the number in a separate group though, by surrounding the digits with parentheses :

Regex.Matches("VA VV_CELL1 3.54 3.55",@"\s+(\d+(\.\d+)?)$")[0].Groups[1]

You need to use Groups[1] because the first group always returns the entire capture

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.