【问题标题】:C# Replace with regexC# 用正则表达式替换
【发布时间】:2014-12-10 17:25:59
【问题描述】:

我是 VB、C# 的新手,并且正在努力使用正则表达式。我想我有以下代码格式可以用我的文件中的空格替换正则表达式匹配。

编辑:每个 cmets,此代码块已更改。

var fileContents = System.IO.File.ReadAllText(@"C:\path\to\file.csv");

fileContents = fileContents.Replace(fileContents, @"regex", "");

regex = new Regex(pattern);
regex.Replace(filecontents, "");
System.IO.File.WriteAllText(@"C:\path\to\file.csv", fileContents);

我的文件格式如下:

"1111111","22222222222","Text that may, have a comma, or two","2014-09-01",,,,,,

到目前为止,我有正则表达式在 ,"", 之间找到任何包含逗号的字符串(第一个或最后一个单元格中从来没有逗号,所以我不担心排除这两个。我在Expresso 中测试正则表达式

(?<=,")([^"]+,[^"]+)(?=",)

我只是不确定如何将该逗号分隔为需要替换的内容。最好的方法是什么?

已解决: 结合 [^"]+ 与后视/前视:

(?<=,"[^"]+)(,)(?=[^"]+",)

最终编辑: 这是我最终的完整解决方案:

//read file contents
var fileContents = System.IO.File.ReadAllText(@"C:\path\to\file.csv");

//find all commas between double quotes
var regex = new Regex("(?<=,\")([^\"]+,[^\"]+(?=\",)");

//replace all commas with ""
fileContents = regex.Replace(fileContents, m => m.ToString().Replace(",", ""));

//write result back to file
System.IO.File.WriteAllText(@"C:\path\to\file.csv", fileContents);

【问题讨论】:

  • Filecontents.Replace 不会对初学者进行正则表达式替换。您创建一个正则表达式 regex = new Regex(pattern);然后你做 regex.Replace(filecontents, replacement);
  • @DStanley 我不想拆分字符串
  • @FlorianSchmidinger 感谢您的解释,我会这样尝试,但仍需要找出正确的正则表达式
  • @RichardN - 当您使用该正则表达式时,它只会找到它替换的单个字符。匹配评估器委托是一个昂贵的回调,其主要目的是对主要的一般替换进行子替换。使用相同的正则表达式,试试这个Console.WriteLine(Regex.Replace(@",""one, two"",", "(?&lt;=,\"[^\"]+),(?=[^\"]+\",)", "")); 然后这个Console.WriteLine(Regex.Replace(@",""one, two"",", "(?&lt;=,\"[^\"]+),(?=[^\"]+\",)", m =&gt; m.ToString().Replace(",", "")));

标签: c# regex visual-studio-2010 csv replace


【解决方案1】:

通过将 [^"]+ 与前向 ?= 和后向 ?&lt;= 组合来解决此问题,以便它找到以 ,"[anything that's not double quotes, one or more times] 开头的字符串,然后有一个逗号,然后以 [anything that's not double quotes, one or more times]", 结尾

(?

【讨论】:

  • 这工作正常。你甚至可以使用(?&lt;=,"[^"]*),(?=[^"]*",) 来处理像delimiter",middle,"delimiter 这样的边缘情况。 +1
  • 是的,我想这也行。它永远不会发生,因为我正在处理的文件是以特定格式自动生成的,字段内的, 仅以数字形式出现,例如10,0001,000,000。我想我什至可以使用(?=[0-9]+),(?=[0-9]+)
  • 你去,这是有道理的。
【解决方案2】:

尝试用这个解析出所有列:

 Regex regex = new Regex("(?<=\").*?(?=\")");

那么你可以这样做:

 foreach(Match match in regex.Matches(filecontents))
 {
      fileContents = fileContents.Replace(match.ToString(), match.ToString().Replace(",",string.Empty))
 }

可能没有那么快,但应该可以。

【讨论】:

    【解决方案3】:

    我可能会使用 Regex.Replace 的重载,它需要一个委托来返回替换的文本。 当您有一个简单的正则表达式来识别模式但您需要为替换做一些不那么简单(复杂逻辑)的事情时,这很有用。

    我发现让你的正则表达式保持简单会在你以后尝试维护它们时带来好处。

    注意:这类似于@Florian 的回答,但此替换将自身限制为仅在匹配的文本中进行替换。

    string exp = "(?<=,\")([^\"]+,[^\"]+)(?=\",)";
    var regex = new Regex(exp); 
    string replacedtext = regex.Replace(filecontents, m => m.ToString().Replace(",",""))
    

    【讨论】:

    • 在这种情况下input 会是filecontents吗?
    【解决方案4】:

    你所拥有的是一种不规则的语言。这是因为逗号可能意味着不同的东西,具体取决于它在文本流中的位置。奇怪的正则表达式旨在解析正则语言,其中逗号表示相同的意思,而不管它在文本流中的什么位置。不规则语言需要的是解析器。事实上,正则表达式主要用于在将字符串输入解析器之前对其进行标记。

    虽然您尝试做的事情可以使用正则表达式来完成,但它可能会非常慢。例如,您可以使用以下内容(即使逗号是字段中的第一个或最后一个字符也可以使用)。但是,每次找到逗号时,它都必须前后扫描以检查它是否在两个引号字符之间。

     (?<=,"[^"]*),(?=[^"]*",)
    

    另请注意,它们可能是您尚未发现的这种方法的缺陷。我不知道您是否有此问题,但通常在 CSV 文件中,您可以在字段中间使用引号字符,其中可能还有逗号。在这些情况下,像 MS Excel 这样的应用程序通常会将引号加倍以表明它不是字段的结尾。像这样:

    "1111111","22222222222","Text that may, have a comma, Quote"" or two","2014-09-01",,,,,,
    

    在这种情况下,您将无法使用正则表达式。

    谢天谢地,处理 CSV 文件的代码非常简单:

        public static IList<string> ParseCSVLine(string csvLine)
        {
            List<string> result = new List<string>();
            StringBuilder buffer = new StringBuilder();
    
            bool inQuotes = false;
            char lastChar = '\0';
    
            foreach (char c in csvLine)
            {
                switch (c)
                {
                    case '"':
                        if (inQuotes)
                        {
                            inQuotes = false;
                        }
                        else
                        {
                            if (lastChar == '"')
                            {
                                buffer.Append('"');
                            }
                            inQuotes = true;
                        }
                        break;
    
                    case ',':
                        if (inQuotes)
                        {
                            buffer.Append(',');
                        }
                        else
                        {
                            result.Add(buffer.ToString());
                            buffer.Clear();
                        }
                        break;
    
                    default:
                        buffer.Append(c);
                        break;
                }
    
                lastChar = c;
            }
            result.Add(buffer.ToString());
            buffer.Clear();
    
            return result;
        }
    

    附言。 CSV 文件经常遇到另外几个问题,我给出的代码无法解决这些问题。首先是如果一个字段的中间有一个行尾字符会发生什么?其次是你怎么知道 CSV 文件的字符编码是什么?这两个问题中的前者很容易通过稍微修改我的代码来解决。但是,如果不与向您提供文件的人达成某种协议,第二个几乎是不可能的。

    【讨论】:

    • 感谢您提供所有详细信息。这是非常有用的。澄清一下,我的正则表达式是(?&lt;=,"[^"]+),(?=[^"]+",) 使用+ 而不是*,因此它需要,", 之间的一个或多个字符
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-21
    • 2022-06-12
    • 1970-01-01
    • 1970-01-01
    • 2019-01-24
    • 1970-01-01
    相关资源
    最近更新 更多