【问题标题】:How to convert a multi-line delimited string to a List<class>如何将多行分隔字符串转换为 List<class>
【发布时间】:2021-10-17 05:42:54
【问题描述】:

我有一个用新行分隔的字符串。
我可以将它拆分为 4 个不同的列表项,但我还需要拆分每个字符串的内容,其中项目使用 | 字符作为分隔符。

内部值使用标签,例如BR=KS=。 我想使用这些标签的值来生成新的类对象。
该类名为BIRIM;它具有与字符串中的标签相对应的属性名称。

我的字符串:

BR=PALET90|KS=90|IS=1
BR=PALET60|KS=60|IS=1
BR=EUROPALET|KS=55|IS=1
BR=EUROPALET66|KS=66|IS=1
BR=PALET|KS=75|IS=1

我当前的代码:

 public class BIRIM {
  public string BR {get;set;}
  public int KS {get;set;}
  public int IS {get;set;}
}

 string birim = node2["BIRIMLER"]?.InnerText;

 string[] birimlerim = birim.Split(
      new[] { Environment.NewLine },
      StringSplitOptions.None
 );

【问题讨论】:

    标签: c# split delimiter


    【解决方案1】:

    从技术上讲,你可以Split几次次:

     using System.Linq;
    
     ...
    
     string source = 
       @"BR=PALET90|KS=90|IS=1
         BR=PALET60|KS=60|IS=1
         BR=EUROPALET|KS=55|IS=1
         BR=EUROPALET66|KS=66|IS=1
         BR=PALET|KS=75|IS=1";
    
      ...
    
      var myList = source
        .Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
        .Select(line => line
           .Split('|')
           .Select(item => item.Split('='))
           .ToDictionary(item => item[0].Trim(), item => item[1]))
        .Select(dict => new BIRIM() {
          BR = dict["BR"],
          KS = int.Parse(dict["KS"]),
          IS = int.Parse(dict["IS"])
        })
        .ToList();
    

    不过,我建议在BIRIM 类中实现TryParse 方法,必要时让这个类自行解析

    using System.Text.RegularExpressions;
    
    ...
    
    public class BIRIM {
    
      ...
    
      public static bool TryParse(string source, out BIRIM result) {
        result = null;
    
        if (string.IsNullOrWhiteSpace(source))
          return false;
    
        string br = Regex.Match(source, @"BR\s*=\s*(\w+)").Groups[1].Value;
        string KS = Regex.Match(source, @"KS\s*=\s*([0-9]+)").Groups[1].Value;
        string IS = Regex.Match(source, @"IS\s*=\s*([0-9]+)").Groups[1].Value;
    
        if (!string.IsNullOrEmpty(br) && 
             int.TryParse(KS, out int aks) && 
             int.TryParse(IS, out int ais)) {
          result = new BIRIM() {
            BR = br,
            KS = aks,
            IS = ais,
          };
    
          return true;
        }
    
        return false;
      }
    }
    

    然后就可以实现加载了

      var myList = source
        .Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
        .Select(line => BIRIM.TryParse(line, out var value) ? value : null)
        .Where(value => value != null)
        .ToList();
    

    【讨论】:

    • TryParse 方法中总有一个哥特式:如果 TryParse 失败,正确的行为应该是什么?在这里,您只是忽略了“错误”的行。这意味着实际上吞下了一个问题(源字符串在某种程度上是错误的?)并忽略它。根据情况,这可能不是最好的选择。一般来说,我更喜欢将“逻辑”错误作为错误处理,而不是像什么都没发生一样继续处理:它通常会导致程序中进一步的错误/不当行为,可能更难理解和修复
    • Gian Paolo:我想我应该用TryParse 来展示单一职责 原则:类应该为自己解析。至于实现,我们可以忽略解析错误或抛出异常,甚至可以收集错误然后抛出带有问题列表的异常。 TryParse 也一样:我的代码容忍块交换(首先是 KS,然后是 BR),这不是最佳策略所必需的
    • TryParse 方法本身以及您在示例中实现的方式没有错,也满足 SRP。当有人忽略错误的返回值时,使用它是“危险的”。有时它可能是正确的选择,大多数时候我认为(可能在这种情况下也是如此),程序应该以某种方式处理问题“输入在某种程度上是错误的,我应该做一些事情而不是忽略错误的输入” .当然,决定如何处理错误输入是调用者的责任,而不是 BRIM 类本身。
    【解决方案2】:

    另一种选择。
    使用Regex.Matches()(指定RegexOptions.Multiline)解析整个多行内容,迭代MatchCollection项目以使用提取的值构建新的BIRIM对象。

    string pattern = @"^BR=(?<br>.*?)\|KS=(?<ks>.*?)\|IS=(?<is>.*?)$";
    string innerText = node2["BIRIMLER"]?.InnerText;
    
    var birims = Regex.Matches(innerText, pattern, RegexOptions.Multiline)
        .OfType<Match>().Select(m => 
            new BIRIM(
                m.Groups["br"].Value,
                int.Parse('0' + m.Groups["ks"].Value.Trim()),
                int.Parse('0' + m.Groups["is"].Value.Trim())))
        .ToList();
    

    这会处理空的KSIS 值,将空/空值转换为0
    根据需要进行调整。


    我已向您的 BIRIM 类添加了一个构造函数,该类接受与其属性类型匹配的参数。
    如果无法修改类结构,请使用语法(new T() { PropertyName = PropertyValue }):

    public class BIRIM
    {
        public BIRIM(string sbr, int sks, int sis) {
            BR = sbr; KS = sks; IS = sis;
        }
    
        public string BR { get; set; }
        public int KS { get; set; }
        public int IS { get; set; }
    }
    

    【讨论】:

      【解决方案3】:

      你必须多次拆分

      一个实现可能如下,但请考虑将其拆分为更多功能,它会更具可读性并且您可以解析转换后的值。

          private static List<BIRIM> ParseBirim(string birimText)
          {
              var birims = new List<BIRIM>();
      
              string[] birimlerim = birimText.Trim().Split(Environment.NewLine);
      
              foreach (string birim in birimlerim)
              {
                  string[] bki = birim.Split('|');
      
                  birims.Add(new BIRIM
                  {
                      BR = bki[0].Split('=')[1],
                      KS = Convert.ToInt32(bki[1].Split('=')[1]),
                      IS = Convert.ToInt32(bki[2].Split('=')[1]),
                  });
              }
      
              return birims;
          }
      

      【讨论】:

        【解决方案4】:

        试试这个而不是 Environment.NewLine :

         string[] birimlerim = birim.Split(new string[] { "\r\n" }, StringSplitOptions.None);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-06-05
          • 1970-01-01
          • 1970-01-01
          • 2011-09-08
          • 2018-07-14
          • 1970-01-01
          • 1970-01-01
          • 2021-08-20
          相关资源
          最近更新 更多