从一个字符读取到另一个字符的字符串

5
我有以下字符串:

FB:77:CB:0B:EC:09{W: 0,623413, X: 0,015374, Y: 0,005306, Z: -0,781723}

我想以浮点数/小数的形式读取W、X、Y、Z的值。这些值的长度不总是相同的。
如何在不使用相对位置的情况下从一个字符读取到另一个字符?

2
我会使用正则表达式。 - Aldert
这个字符串看起来像是一个不正确的JSON字符串。这个字符串的本质是什么? - Zack ISSOIR
这些值来自于惯性测量单元(IMU),代表四元数中的方向。在这之前是IMU的Mac地址,例如FB:77:CB:0B:EC:09。 - pvand
你只需要一个整数吗?比如 W = 0X = 0Y = 0Z = 0 - Kristoffer Lerbæk Pedersen
正如Aldert所言,这可能是尝试使用正则表达式的好地方。 如果您首先剥离 { 和之前的字符以及尾随的 },则可能会发现更容易创建正则表达式。 - Jon Skeet
你应该发布多个样本数据吗?例如,如果每行中的W、X、Y、Z都是固定的,那么解决方案将非常简单? - Gaurav P
4个回答

11

我建议先手动删除“外部”部分,然后再使用正则表达式匹配“内部”部分,这样可以使正则表达式尽可能简单。

以下是一个完整的示例,使用一种返回结果为Dictionary<string, string>的方法。不清楚如何将给出的示例值(例如“0,623413”)转换为整数,但我认为这应该作为初始解析的一个独立任务。

我假设从值中去除所有尾随逗号也是可行的:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

class Test
{
    static void Main()
    {
        string input = "FB:77:CB:0B:EC:09{W: 0,623413, X: 0,015374, Y: 0,005306, Z: -0,781723}";
        var parsed = Parse(input);
        foreach (var entry in parsed)
        {
            Console.WriteLine($"Key = '{entry.Key}', Value = '{entry.Value}'");
        }        
    }

    static readonly Regex regex = new Regex(@"(?<key>[A-Z]+): (?<value>[-\d,]+)");
    static IDictionary<string, string> Parse(string input)
    {
        int openBrace = input.IndexOf('{');
        if (openBrace == -1)
        {
            throw new ArgumentException("Expected input to contain a {");
        }
        if (!input.EndsWith("}"))
        {
            throw new ArgumentException("Expected input to end with }");
        }
        string inner = input.Substring(openBrace + 1, input.Length - openBrace - 2);
        var matches = regex.Matches(inner);
        return matches.Cast<Match>()
            .ToDictionary(match => match.Groups["key"].Value,
                          match => match.Groups["value"].Value.TrimEnd(','));
    }
}

输出:

Key = 'W', Value = '0,623413'
Key = 'X', Value = '0,015374'
Key = 'Y', Value = '0,005306'
Key = 'Z', Value = '-0,781723'

将这些值转换为整数可能很简单,只需去掉逗号,修剪前导零,然后使用int.Parse - 但这真的取决于您想要的结果。


1
非常好的回答@JonSkeet。我有一个建议,在您的Parse方法中,为什么不使用IEnumerable <(string,string)>而不是字典? - Zack ISSOIR
1
@ZackISSOIR:因为它更自然地是一个键/值对的字典,我个人认为。我认为OP很可能想通过键查找值。 - Jon Skeet

0
回答你的问题,这个方法会做到:
int GetIntValue(string input, char prefix)
{
  return int.Parse(input.Substring(input.IndexOf($"{prefix}: ") + 3, 1));
}

但是这将会对您的所有样例输入返回 0。为什么我们只解析零呢?因为它们无论如何都会被 int 解析器忽略。

如果,正如我所怀疑的,您不想要一个整数而是完整的数字,请使用类似以下的方法:

decimal GetValue(string input, char prefix)
{
  return decimal.Parse(input.Substring(input.IndexOf($"{prefix}: ") + 3).Split(new[] { ", ", "}" }, StringSplitOptions.None).First());
}

随意用你喜欢的东西替换decimal

像这样调用:

var input = "FB:77:CB:0B:EC:09{W: 0,623413, X: 0,015374, Y: 0,005306, Z: -0,781723}";
var W = GetValue(input, 'W'); // 0.623413
var X = GetValue(input, 'X'); // 0.015374
var Y = GetValue(input, 'Y'); // 0.005306
var Z = GetValue(input, 'Z'); // -0.781723

这段代码的作用是识别前缀的位置,然后从接下来的数字开头解析一个子字符串,直到达到分隔符(,})。

0
static void Main(string[] args) {
        string str = "FB:77:CB:0B:EC:09{W: 0,623413, X: 0,015374, Y: 0,005306, Z: -0,781723}";
        char[] delims = { ':', ' ' };

        var parsed = Parse(str, delims);

        foreach (var p in parsed) {
            Console.WriteLine($"{p.Key} : {p.Value}");
        }
    }

    static Dictionary<string, double> Parse(string input, char[] delims) {
        int first = input.IndexOf('{') + 1;
        int second = input.IndexOf('}');
        string str2 = input.Substring(first, second - first);

        string[] strArray = str2.Split(delims, StringSplitOptions.RemoveEmptyEntries);
        Dictionary<string, double> pairs = new Dictionary<string, double>();

        for (int i = 1; i < strArray.Length; i++) {
            if (double.TryParse(strArray[i].TrimEnd(','), out double result)) {
                pairs.Add(strArray[i - 1], result);
            }

            i++;
        }

        return pairs;
    }

欢迎来到StackOverflow!我们需要提供详细信息的长篇回答。 - new QOpenGLWidget

-1

这里是另一个正则表达式示例,它将数字解析为十进制,并包括加号和减号。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Globalization;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string input = "FB:77:CB:0B:EC:09{W: 0,623413, X: 0,015374, Y: 0,005306, Z: -0,781723}";
            string pattern = @"W:\s*(?'W'[-+]?\d+,\d+),\s*X:\s*(?'X'[-+]?\d+,\d+),\s*Y:\s*(?'Y'[-+]?\d+,\d+),\s*Z:\s*(?'Z'[-+]?\d+,\d+)";
            CultureInfo info = new CultureInfo("en");
            info.NumberFormat.NumberDecimalSeparator = ",";

            Match match = Regex.Match(input, pattern);

            decimal W = decimal.Parse(match.Groups["W"].Value, info);
            decimal X = decimal.Parse(match.Groups["X"].Value, info);
            decimal Y = decimal.Parse(match.Groups["Y"].Value, info);
            decimal Z = decimal.Parse(match.Groups["Z"].Value, info);

        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接