【问题标题】:Regular expression to remove whitespace around a comma, except when quoted用于删除逗号周围空格的正则表达式,引用时除外
【发布时间】:2013-10-21 15:25:33
【问题描述】:

我有一个 CSV 文件,其中包含类似这样的行:

1,  4,     2, "PUBLIC, JOHN Q" ,ACTIVE , 1332

我正在寻找一个正则表达式替换,它将与这些行匹配并吐出类似这样的内容:

1,4,2,"PUBLIC, JOHN Q",ACTIVE,1332

我认为这很容易:我创建了表达式 ([ \t]+,) 并将其替换为 ,。我做了一个补充表达式(,[ \t]+) 替换为,,我认为我已经实现了右修剪和左修剪字符串的好方法。

...但后来我注意到我的"PUBLIC, JOHN Q" 现在是"PUBLIC,JOHN Q",这不是我想要的。 (注意逗号后面的空格现在已经消失了)。

什么是适当的表达方式来修剪逗号前后的空白,但保留引用的文本不变?

更新

为了澄清,我正在使用一个应用程序来处理文件。这个应用程序允许我定义多个正则表达式替换;它不提供解析功能。虽然这可能不是理想的机制,但它肯定会胜过为这个文件制作另一个应用程序。

【问题讨论】:

  • 为什么不解析?
  • 使用 CSV 解析器 - 不要试图重新发明轮子!查看Microsoft.VisualBasic.FileIO.TextFieldParser
  • 您将有一个正则表达式的怪物,因为它必须考虑检测它是否在引号之间,以及这些引号是否已被转义。正如其他评论者所说:解析,然后在没有空格的情况下重建。
  • 可能是错误的工作工具:programmers.stackexchange.com/questions/166454/…
  • @Ralf 我用 C# 和 .Net 对其进行了标记,因为它具有与 perl/php/java/javascript 不同的正则表达式;我只是想澄清一下。我正在使用的应用程序是用 C# 编写的内部应用程序。

标签: c# .net regex csv replace


【解决方案1】:

如果你的工具使用的引擎是C#正则表达式引擎,那么你可以试试下面的表达式:

(?<!,\s*"(?:[^\\"]|\\")*)\s+(?!(?:[^\\"]|\\")*"\s*,)

用空字符串替换。

这些家伙的回答假设引号是平衡的,并使用计数来确定空格是否是引用值的一部分。

我的表达式查找不属于引用值的所有空格。

RegexHero Demo

【讨论】:

  • 嗨@Sniffer (?
  • @lucacerone 自从我使用正则表达式已经有一段时间了,所以你需要检查 C# 文档以确保,但我记得这是一个消极的回顾。
【解决方案2】:

这样的事情可能会完成这项工作:

(?<!(^[^"]*"[^"]*(("[^"]*){2})*))[\t ]*,[ \t]*

匹配[\t ]*,[ \t]*,仅当前面没有奇数个引号时。

【讨论】:

    【解决方案3】:

    使用一些 CSV 库或自己解析文件会容易得多,IMO 应该是这里的首选。

    但如果你真的坚持使用正则表达式,你可以使用这个:

    "\s+(?=([^\"]*\"[^\"]*\")*[^\"]*$)"
    

    并用空字符串替换它 - ""

    此正则表达式匹配一个或多个空格,后跟偶数个引号。这当然只有在你有平衡报价的情况下才有效。

    (?x)       # Ignore Whitespace
    \s+        # One or more whitespace characters       
    (?=        # Followed by 
       (          # A group - This group captures even number of quotes
         [^\"]*     # Zero or more non-quote characters
         \"         # A quote
         [^\"]*     # Zero or more non-quote characters
         \"         # A quote 
       )*         # Zero or more repetition of previous group
       [^\"]*     # Zero or more non-quote characters
       $          # Till the end
    )          # Look-ahead end
    

    【讨论】:

      【解决方案4】:
              string format(string val)
              {
                  if (val.StartsWith("\"")) val = " " + val;
                  string[] vals = val.Split('\"');
                  for (int i = 0; i < vals.Length; i += 2) vals[i] = vals[i].Replace(" ", "").Replace("\t", "");
                  return string.Join("\t", vals);
              }
      

      如果您在两者之间正确关闭带引号的字符串,这将起作用

      【讨论】:

        【解决方案5】:

        忘记正则表达式(请参阅 Bart 对问题的评论,正则表达式不适用于 CSV)。

        public static string ReduceSpaces( string input )
        {
            char[] a = input.ToCharArray();
            int placeComma = 0, placeOther = 0;
            bool inQuotes = false;
            bool followedComma = true;
            foreach( char c in a ) {
                inQuotes ^= (c == '\"');
                if (c == ' ') {
                    if (!followedComma)
                        a[placeOther++] = c;
                }
                else if (c == ',') {
                    a[placeComma++] = c;
                    placeOther = placeComma;
                    followedComma = true;
                }
                else {
                    a[placeOther++] = c;
                    placeComma = placeOther;
                    followedComma = false;
                }
            }
            return new String(a, 0, placeComma);
        }
        

        演示:http://ideone.com/NEKm09

        【讨论】:

          猜你喜欢
          • 2020-12-28
          • 1970-01-01
          • 2017-03-15
          • 1970-01-01
          • 1970-01-01
          • 2017-07-09
          • 1970-01-01
          • 2014-08-22
          • 1970-01-01
          相关资源
          最近更新 更多