首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C#字符串约定解析

C#字符串约定解析
EN

Stack Overflow用户
提问于 2009-04-01 21:58:14
回答 8查看 2.9K关注 0票数 3

我对C#比较陌生,并且有一个用户输入字符串(我希望是有效的)。

此字符串将组成信息的多个部分和子部分。

例如:

代码语言:javascript
复制
1-7 will //represent values 1 2 3 4 5 6 7

3:.25:7 //will be the numbers contained between 3 and 7 in increments of .25 
        // (3 3.25 3.5 3.75 4 ... 6.75 7)
1,4,5  //will represent values 1 4 5

我希望能够遍历与此类似的单个字符串,并得到与用分号(;)分隔的数据一样多的数组。

主要目标是解析类似下面这样的东西:

代码语言:javascript
复制
1-7;3:.25:10;1,5,9;4-7

由于上面有4个“数据集”,我应该创建4个包含这些值的新数组。如果我有n个“数据集”,我应该创建n个新的数组。

稍后,我将使用所有组合以嵌套的方式遍历数组。

此外,如果可能(不是必需的),能够进行如下表示形式的某种混合:

代码语言:javascript
复制
1-7,9,16:2:20;

我希望我在这里试图实现的东西在我的示例中是有意义的。

谢谢!

EN

回答 8

Stack Overflow用户

发布于 2009-04-01 22:03:40

好吧,可能会有一个聪明的RegEx的答案,我会用我最喜欢的string.Split()函数试一试。

作为第一步,您可以将输入字符串拆分为';‘

代码语言:javascript
复制
string[] datasets = inputString.Split(';');

至于你的最后一点,看起来逗号',‘的作用大同小异,你可以把它和Split(';', ',')合并,或者用分隔开

代码语言:javascript
复制
string[] parts = datasets[i].Split(',');

然后,部件是以下三种情况之一:单个数字、范围或阶梯范围。

您可以使用string.IndexOf()和/或

代码语言:javascript
复制
string[] rangeParts = parts[j].Split('-');
string[] steppedParts = parts[j].Split(':');

结果的长度应分别为2和3。

然后使用TryParse()检查生成的字符串,由于使用了标点符号,因此您最好修复区域性:

代码语言:javascript
复制
bool valid = double.TryParse(parts[k], 
  System.Globalization.NumberStyles.AllowDecimalPoint, 
  System.Globalization.CultureInfo.InvariantCulture, out value);

这些都是零件,需要一些组装。

票数 3
EN

Stack Overflow用户

发布于 2009-04-01 22:11:05

我建议使用正则表达式。首先,我会使用下面的表达式将其分成几个部分。

代码语言:javascript
复制
^((?<section>[^;]+)(;|$))+

然后将每个部分拆分为子部分。

代码语言:javascript
复制
^((?<subsection>[^,]+)(,|$))+

现在匹配三种可能的子节类型。

代码语言:javascript
复制
(?<value>^[0-9]+$)|
(?<range>^[0-9]+-[0-9]+$)|
(?<rangewithstep>^[0-9]+:\.[0-9]+:[0-9]+$)

最后,您必须分析范围类型子部分。

代码语言:javascript
复制
^(?<start>[0-9]+)-(?<end>[0-9]+)$

^(?<start>[0-9]+):(?<step>\.[0-9]+):(?<end>[0-9]+)$

现在是将提取的字符串解析为数字并将其添加到数组中的问题。

我把所有的东西放在一个小的控制台应用程序中,它可以做这件事。它远非完美--没有错误处理,什么都没有,只是解析一个演示输入。我合并了前面提到的一些表达式,以获得更紧凑的代码,可能还会更好。

代码语言:javascript
复制
using System;
using System.Text.RegularExpressions;
using System.Globalization;

namespace RangeParser
{
    class Program
    {
        static void Main(string[] args)
        {
            String input = "1-7,9,16:2:20;1-7; 3:.75 : 10;1,5,9;4-7";

            Match sections = (new Regex(@"^((?<section>[^;]+)(;|$))+")).Match(input.Replace(" ", ""));

            foreach (Capture section in sections.Groups["section"].Captures)
            {
                Console.Write("Section ");

                Match subsections = (new Regex(@"^((?<subsection>[^,]+)(,|$))+")).Match(section.Value);

                foreach (Capture subsection in subsections.Groups["subsection"].Captures)
                {
                    Match subsectionparts = (new Regex(@"^(?<start>[0-9]*\.?[0-9]+)(((:(?<step>[0-9]*\.?[0-9]+):)|-)(?<end>[0-9]*\.?[0-9]+))?$")).Match(subsection.Value);

                    if (subsectionparts.Groups["start"].Length > 0)
                    {
                        Decimal start = Decimal.Parse(subsectionparts.Groups["start"].Value, CultureInfo.InvariantCulture);
                        Decimal end = start;
                        Decimal step = 1;

                        if (subsectionparts.Groups["end"].Length > 0)
                        {
                            end = Decimal.Parse(subsectionparts.Groups["end"].Value, CultureInfo.InvariantCulture);

                            if (subsectionparts.Groups["step"].Length > 0)
                            {
                                step = Decimal.Parse(subsectionparts.Groups["step"].Value, CultureInfo.InvariantCulture);
                            }
                        }

                        Decimal current = start;

                        while (current <= end)
                        {
                            Console.Write(String.Format("{0} ", current));

                            current += step;
                        }
                    }
                }

                Console.WriteLine();
            }

            Console.ReadLine();
        }
    }
}

更新

修改为允许类似“1.5:0.2:3.6”的内容。

更新

为什么使用十进制而不是单精度或双精度?

输入中的数字是十进制数字,不能精确地用single或double表示,因为它们使用基数2表示。例如,0.1由单个值0.100000001490116119384765625表示。

代码语言:javascript
复制
Single x = 0.0F;

for (int i = 0; i < 8; i++)
{
   x += 0.1F;
}

Console.WriteLine(x);

此程序将在仅8次迭代后打印0.8000001。在1000次迭代之后,错误增长到0.00095,显示99.99905而不是100.0,并且在一百万次迭代之后,结果是100,958.3而不是100,000。

对于decimal没有这样的错误,因为decimal使用以10为基数的表示法,并且能够准确地表示像0.1这样的十进制数。

票数 2
EN

Stack Overflow用户

发布于 2009-04-01 22:21:15

下面是一些C#代码,它们可以完成您想要的操作:

代码语言:javascript
复制
    var results = ParseExpression("1-7;3:.25:10;1,5,9;4-7");

    private static List<List<float>> ParseExpression(string expression)
    {
        // "x-y" is the same as "x:1:y" so simplify the expression...
        expression = expression.Replace("-", ":1:");

        var results = new List<List<float>>();
        foreach (var part in expression.Split(';'))
            results.Add(ParseSubExpression(part));

        return results;
    }

    private static List<float> ParseSubExpression(string part)
    {
        var results = new List<float>();

        // If this is a set of numbers...
        if (part.IndexOf(',') != -1)
            // Then add each member of the set...
            foreach (string a in part.Split(','))
                results.AddRange(ParseSubExpression(a));
        // If this is a range that needs to be computed...
        else if (part.IndexOf(":") != -1)
        {
            // Parse out the range parameters...
            var parts = part.Split(':');
            var start = float.Parse(parts[0]);
            var increment = float.Parse(parts[1]);
            var end = float.Parse(parts[2]);

            // Evaluate the range...
            for (var i = start; i <= end; i += increment)
                results.Add(i);
        }
        else
            results.Add(float.Parse(part));

        return results;
    }
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/707508

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档