有没有更好的方法来解析字符串?

38

我想知道在.NET中是否有一种内置的方法来解析字符串的位。

例如,我有以下字符串:

"bsarbirthd0692"

由以下部分组成,稍后将与数据进行交叉引用:

Indexes   Purpose
0-3       (name)
4-9       (description)
10-13     (date mm-yy)
我希望你能提供像本地人一样的内容:
string name, desc, date;
string.ParseFormat("{0:4}{1:5}{2:4}", "bsarbirthd0692", out name, out desc, out date);

在.NET中是否有本地方法或者流行的库可以实现这个功能?


9
自己实现这个并不太难,毕竟只是将子字符串调用包装起来而已... - Alex K.
2
你可以使用子字符串来完成这个任务,因为格式是固定长度的。你也可以使用正则表达式,但由于格式是固定宽度的,所以似乎没有必要。 - iandotkelly
为什么不使用JSON?或XML? - NoBugs
2
支持对string.Format提出逆函数建议。 - Stefan Hanke
5个回答

50

既然已知格式并且不应更改,那么使用子字符串就可以解决问题。

string data = "bsarbirthd0692";
string name, desc, date;
name = data.Substring(0, 4);
desc = data.Substring(4, 6);
date = data.SubString(10);

编辑

你还可以创建扩展方法来实现任何你想要的功能。这显然比之前的建议更复杂。

public static class StringExtension
{
    /// <summary>
    /// Returns a string array of the original string broken apart by the parameters
    /// </summary>
    /// <param name="str">The original string</param>
    /// <param name="obj">Integer array of how long each broken piece will be</param>
    /// <returns>A string array of the original string broken apart</returns>
    public static string[] ParseFormat(this string str, params int[] obj)
    {
        int startIndex = 0;
        string[] pieces = new string[obj.Length];
        for (int i = 0; i < obj.Length; i++)
        {
            if (startIndex + obj[i] < str.Length)
            {
                pieces[i] = str.Substring(startIndex, obj[i]);
                startIndex += obj[i];
            }
            else if (startIndex + obj[i] >= str.Length && startIndex < str.Length)
            {
                // Parse the remaining characters of the string
                pieces[i] = str.Substring(startIndex);
                startIndex += str.Length + startIndex;
            }

            // Remaining indexes, in pieces if they're are any, will be null
        }

        return pieces;
    }
}

使用方式 1:

string d = "bsarbirthd0692";
string[] pieces = d.ParseFormat(4,6,4);

结果:

在此输入图片描述

用法2:

string d = "bsarbirthd0692";
string[] pieces = d.ParseFormat(4,6,4,1,2,3);

结果:

enter image description here


5
赞同(Upvoted):使代码简单易懂。 - frenchie
3
即使已知格式,也可能会发生变化。例如,如果数据不在您的控制范围内。但是,在使用数据之前添加“长度检查”是很容易的。 - Tim Schmelter
太棒了!谢谢你! - Sarah Bailey

16

你可以使用正则表达式来实现这个功能

string str= "bsarbirthd0692";
var regex = "(?<name>.{4})(?<desc>.{6})(?<date>.{4})";
MatchCollection matches = Regex.Matches(str, regex);
foreach(Match m in matches){
    Console.WriteLine(m.Groups["name"].ToString());
    Console.WriteLine(m.Groups["desc"].ToString());
    Console.WriteLine(m.Groups["date"].ToString());
}

1
正则表达式是我立刻想到的解决方案。几乎完全符合OP所需的语义。 - mellamokb
6
正则表达式是一把很好的锤子,只要确保你只在钉子上使用它们:D - Luaan
6
正则表达式在这里有点过头了(而且提问者显然是一个正则表达式新手,不需要额外的困惑)。然而,使用命名分组避免完全无法理解对于新手来说是个好的尝试。 - dodgethesteamroller
1
@SarahBourt 或许我没有理解原始问题。如果您了解正则表达式,为什么不在这样一个微不足道的问题上使用它们呢?除非有人已经遇到了您尝试解析的确切文件格式(不太可能),否则怎么可能有任何更简单的本地库呢? - dodgethesteamroller
2
正如我的同事曾经告诉我:“‘不要用锤子来拧螺丝钉’这句话并不意味着你可以用扳手来猛力敲打它们。” - Joker_vD
显示剩余4条评论

11

虽然没有这样的东西,但可以写些东西来实现:

IEnumerable<string> inputString.BreakIntoLengths(4, 6, 4)

带有签名:

public IEnumerable<string> BreakIntoLengths(this string input, params int[] lengths);

非常容易:

public IEnumerable<string> BreakIntoLengths(this string input, params int[] lengths) {

  var pos = 0;
  foreach (var len in lengths) {
    yield return input.Substring(pos, len);
    pos += len;
  }
}

(实际实现中具有一些错误检查。)

NB. 我已经放弃格式化字符串接口:它似乎没有提供任何价值。一旦返回集合,按索引分配条目就很容易了。


如果我调用这个函数,yield 如何工作?有点尴尬地说,我从未见过这个关键字的实际应用。 - Sarah Bailey
1
@SarahBourt 这会使其变得懒惰。当input很长或有许多长度被列出时,急切生成许多字符串。只有被调用者使用的字符串才会被生成,这样做是懒惰的。 - Richard

2
更好的是什么?类似这样的吗?
var listStrings = new List<string>();
var tempIndex = 0;
var indexList = new List<int>{4, 6, 4}
foreach(var length in indexList)
{
    listStrings.Add(string.Substring(tempIndex , length);
    tempIndex += length 
}

2
不,没有内置的方式。我会使用字符串方法如“Substring”:
string name, desc, date;
if (input.Length >= 4)
{
    name = input.Substring(0, 4);
    if (input.Length >= 10)
    {
        desc = input.Substring(4, 6);
        if (input.Length >= 14)
        {
            date = input.Substring(10, 4);
        }
    }
}

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