【问题标题】:Split delimited string and remove escape sequences [duplicate]拆分分隔字符串并删除转义序列[重复]
【发布时间】:2017-11-01 03:51:50
【问题描述】:

我需要拆分一个逗号分隔的字符串,其内容有时在引号之间。一个例子可能是:

1,"TEST",22345,"18,95", Ab"cde

这里的第一个问题是只有在逗号没有被“18,95”之类的引号包围时才拆分字符串。我已经用一个简单的正则表达式做到了。下一个问题是剪掉引号,它们围绕着内容。对于“TEST”和“18,95”,应删除引号。Ab"cde 中的引号应保持不变。到目前为止,这是我的代码:

List<string> results = Regex.Matches(this.Content, @"[\""](.+?)[\""]|[^,]+")
                            .Cast<Match>()
                            .Select(m => m.Value)
                            .Select(s => s.StartsWith("\"") && s.EndsWith("\"") ? s.Remove(1,1).Remove(s.Length-1,1) : s)
                            .ToList();

对于第二个Select,我得到一个ArgumentOutOfRangeException,因为第二个Remove 不再适用于s。我认为它应该可以工作,但不知何故没有。

如果有更好的方法来做到这一点,我很乐意了解它。

【问题讨论】:

  • 您尝试过 CSV 解析器吗?
  • 提示:字符串是不可变的。
  • @WiktorStribiżew 我正在尝试实现一个
  • 你不需要实现一个,它已经存在于 C# 中。您接受的答案将在转义引号中失败。
  • @WiktorStribiżew 你绝对赢了!来自Microsoft.VisualBasic.FileIO 的 TextFieldParser 是要走的路!如果您发布答案,我会选择它为正确的。谢谢

标签: c# regex string


【解决方案1】:

您可以在具有相同名称的命名捕获组中捕获引号之间的值和未加引号的值,并使用Match.Groups["group_name"] 检索匹配的捕获:

List<string> results = Regex.Matches(this.Content, @"[\""](?<value>.+?)[\""]|(?<value>[^,]+)")
    .Cast<Match>()
    .Select(m => m.Groups["value"].Value)
    .ToList();

演示:https://dotnetfiddle.net/M8lJDR

考虑到潜在的空值,将+ 更改为* 并用(?&lt;=^|,)(?=,|$) 包围正则表达式:

List<string> results = Regex.Matches(input,
        @"(?<=^|,)(?:""(?<value>.*?)""|(?<value>[^,]*))(?=,|$)")
    .Cast<Match>()
    .Select(m => m.Groups["value"].Value)
    .ToList();

演示:https://dotnetfiddle.net/WqRD20

【讨论】:

  • 哇。这是一个很好的!完美的。您是否也知道如何调整正则表达式以捕获空的“值”。就像在 1,2,,4 中会有一个空的第三位,这应该导致一个空字符串
  • 只需将量词从+ 更改为*。查看更新的演示
  • 我也想过,但不幸的是,它会在我需要清理的每个“正常”结果之后添加一个空结果
  • @RomanoZumbé:是的,需要额外的分隔符检查。请查看更新后的答案。
【解决方案2】:

也许您可以遍历每个 results 并且:

for (int i=0; i < results.Count; i++)
{
   if (results[i].StartsWith("\"")) 
       results[i] = results[i].Remove(0, 1);

   if (results[i].EndsWith("\""))  
      results[i] = results[i].Remove(results[i].Length - 1, 1);
}

【讨论】:

    【解决方案3】:

    .Substring()怎么样:

    List<string> results = Regex.Matches(content, @"[\""](.+?)[\""]|[^,]+")
                            .Cast<Match>()
                            .Select(m => m.Value)
                            .Select(s => s.StartsWith("\"") && s.EndsWith("\"") 
                                ? s.Substring(1, s.Length - 2) : s)
                            .ToList();
    

    输出:

    1
    TEST
    22345
    18,95
    Ab"cde
    

    注意:不适用于包含超过 2 个引号的部分,即 ""test""work"",1

    【讨论】:

    • 但这正是我不想要的,因为引号仍在结果中
    • @RomanoZumbé 猜猜我错过了。更新了答案以改用.Substring()
    【解决方案4】:

    调用s.Remove(1,1)后,生成的字符串会比s短(保持不变)!

    使用

    s.Remove(1,1).Remove(s.Length-2,1)
    

    s.Remove(s.Length-1,1).Remove(1,1)
    

    而不是

    s.Remove(1,1).Remove(s.Length-1,1)
    

    s="\"" 时,这仍然会失败。为了解决这个问题,您必须更新条件:

    s.StartsWith("\"") && s.EndsWith("\"") && s.Length > 1 ? s.Remove(s.Length-1,1).Remove(1,1) : s
    

    【讨论】:

    • 我已经尝试过了。也不行
    猜你喜欢
    • 1970-01-01
    • 2020-10-03
    • 1970-01-01
    • 1970-01-01
    • 2020-01-07
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    • 2016-02-12
    相关资源
    最近更新 更多