【问题标题】:Is there a way to parse strings better?有没有办法更好地解析字符串?
【发布时间】:2023-04-01 17:05:02
【问题描述】:

我想知道 .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 或流行的库中是否有本地方法可以做到这一点?

【问题讨论】:

  • 自己实现很简单?毕竟它只是包装子字符串调用......
  • 您可以只使用子字符串来执行此操作,因为格式是固定长度的。你也可以使用正则表达式——但这似乎没有必要,因为格式是固定宽度的。
  • 为什么不是 JSON?还是 XML?
  • 支持string.Format的反函数建议。

标签: c# .net string parsing


【解决方案1】:

由于格式是已知的,不应该改变 Substring 应该适合你

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;
    }
}

用法一:

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

结果:

用法2:

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

结果:

【讨论】:

  • 赞成:保持代码简单易懂。
  • “格式是已知的,不应更改”,即使格式已知,它也可以更改。例如,如果数据不在您的控制之下。但是在使用之前添加Length-check 很容易。
  • 很棒的帖子!谢谢!
【解决方案2】:

您可以为此使用正则表达式

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());
}

【讨论】:

  • 正则表达式是我立即想到的解决方案。几乎完全匹配 OP 所需的语义。
  • @mellamokb 正则表达式是一把好锤子。只要确保你只在指甲上使用它们:D
  • 这里的正则表达式太过分了(而且 OP 显然是一个正则表达式处女,不需要额外的混淆)。但是,使用命名组的道具可以避免新手完全无法理解。
  • @SarahBourt 也许我不明白原来的问题。如果您知道正则表达式,为什么不将它们用于这样一个微不足道的问题呢?除非其他人已经遇到了您尝试解析的 exact 文件格式(不太可能),否则怎么会有任何更简单的本机库?
  • @Luaan 正如我的同事曾经告诉我的,““不要用锤子拧螺丝”这句话并不意味着你可以用扳手来拧螺丝。”
【解决方案3】:

没有类似的东西,但是写一些东西来实现:

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;
  }
}

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

注意。我已经删除了类似接口的格式字符串:它似乎没有提供任何价值。集合返回后,很容易按索引分配条目。

【讨论】:

  • 如果我调用这个函数,yield 是如何工作的?有点尴尬地说我从未见过该关键字在起作用
  • @SarahBourt 它让它变得懒惰。当input 很长,或者列出的长度很多时,急切会生成很多字符串。懒惰只会生成调用者使用的那些。
【解决方案4】:

从什么方面更好?像这样?

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 
}

【讨论】:

    【解决方案5】:

    不,没有内置方法。我会使用像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);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-27
      • 2020-07-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多