C#中的正则表达式替换

57
我对使用正则表达式还比较陌生,根据我读过的一些教程,我无法正确地格式化Regex.Replace中的这一步骤。
以下是我正在处理的情况...当我从列表框中提取数据时,我想将其格式化为类似于CSV的格式,然后保存文件。在这种情况下,使用Replace选项是否是理想的解决方案?
在正则表达式格式化示例之前。
FirstName LastName Salary    Position
-------------------------------------
John      Smith    $100,000.00  M

正则表达式替换后的建议格式

John Smith,100000,M

当前格式化状态输出:

John,Smith,100000,M

*注意 - 我是否可以用空格替换第一个逗号?

我的代码片段

using(var fs = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write))
{
    using(var sw = new StreamWriter(fs))
    {
        foreach (string stw in listBox1.Items)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(stw);

            //Piecing the list back to the original format
            sb_trim = Regex.Replace(stw, @"[$,]", "");
            sb_trim = Regex.Replace(sb_trim, @"[.][0-9]+", "");
            sb_trim = Regex.Replace(sb_trim, @"\s", ",");
            sw.WriteLine(sb_trim);
        }
    }
}

使用正则表达式,44.66将被替换为44 - Anirudha
刚刚重新编辑了我的陈述...我正在将100,000.00转换为100000。是的,当我写回csv格式时,我会忽略分。 - Curtis
请尽量不要使用太多的粗体字 - 我已经删除了所有的粗体字,并修复了您不完整的Dispose调用,所以代码看起来没问题。 - Alexei Levenkov
@Curtis 你应该使用 [.]0+(?=\s) - Anirudha
@Anirudh,使用\d+是否更好?也许不总是.00。 - Zenexer
@AlexeiLevenkov 每当我修复代码时,我的修改都被拒绝。现在看起来好多了。 - Zenexer
5个回答

81
你可以使用两个 replace 来实现这个。
//let stw be "John Smith $100,000.00 M"

sb_trim = Regex.Replace(stw, @"\s+\$|\s+(?=\w+$)", ",");
//sb_trim becomes "John Smith,100,000.00,M"

sb_trim = Regex.Replace(sb_trim, @"(?<=\d),(?=\d)|[.]0+(?=,)", "");
//sb_trim becomes "John Smith,100000,M"

sw.WriteLine(sb_trim);

这样做会进行很多不必要的工作,可能对性能也不太好。如果你要这样做,至少设置一个超时时间。 - Zenexer
@Anirudh 我明白他想做什么。我下面有一个一行的答案,但我不确定它是否有效。 - Zenexer
1
@Zenexer,每当使用正则表达式时,性能都会受到影响 - 是否重要完全取决于具体情况。 - Moo-Juice
@Moo-Juice 当然是真的,这就是为什么我更喜欢避免使用它们。当它们被使用时,最好预编译它们。 - Zenexer

22

试试这个:

sb_trim = Regex.Replace(stw, @"(\D+)\s+\$([\d,]+)\.\d+\s+(.)",
    m => string.Format(
        "{0},{1},{2}",
        m.Groups[1].Value,
        m.Groups[2].Value.Replace(",", string.Empty),
        m.Groups[3].Value));

这是一个相当简洁的答案,至少在正则表达式中是如此。

  • (\D+): 第一组捕获。一个或多个非数字字符。
  • \s+\$: 一个或多个空格字符,然后是一个美元符号 ($)。
  • ([\d,]+): 第二组捕获。一个或多个数字和/或逗号。
  • \.\d+: 小数点,然后至少一个数字。
  • \s+: 一个或多个空格字符。
  • (.): 第三组捕获。任何非换行符的字符。

第二个捕获组还需要去掉逗号。您可以使用另一个正则表达式来实现这一点,但这真的没有必要,并且会影响性能。这就是为什么我们需要使用Lambda表达式和字符串格式来拼接替换的原因。如果不是为了这个,我们可以直接将其用作替换,而不是使用Lambda表达式:

"$1,$2,$3"

谢谢,是的,我尝试过对我的正则表达式进行分组,但似乎只是让情况变得更加复杂,所以我回归到了基础知识。我也会尝试这个方法。 - Curtis
可能有一些方法可以避免组中的逗号,但我不知道。这里肯定有更熟悉.NET特定正则表达式的人,也许他们会知道。 - Zenexer
@Anirudh,根据MSDN的说法并非如此。 - Zenexer
这是关于编程的内容,翻译成中文如下:它是一个非捕获组,但仍然可以在另一个组中捕获它,即它仍然会被捕获在group2中... - Anirudha
啊,使用(?<=)怎么样? - Zenexer
+1 for the lambda...它让我能够轻松地执行一些我需要在结果上进行的原地操作,然后重新组合匹配。 - Timothy Lee Russell

4
请添加以下两行代码。
var regex = new Regex(Regex.Escape(","));
sb_trim = regex.Replace(sb_trim, " ", 1);

如果sb_trim = John,Smith,100000,M,上述代码将返回 "John Smith,100000,M"。

1

为了简便起见,您只需要一个货币数字。

Regex.Replace(yourcurrency, "[^0-9]","")

1

这一定能完成任务:

var result=Regex.Replace("John      Smith    $100,000.00  M", @"^(\w+)\s+(\w+)\s+\$([\d,\.]+)\s+(\w+)$","$1,$2,$3,$4");

//result: "John,Smith,100,000.00,M"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接