【问题标题】:C# RegEx to find empty cells in pipe delimited fileC# RegEx 在管道分隔文件中查找空单元格
【发布时间】:2013-08-23 22:43:22
【问题描述】:

我正在寻找有关 RegEx 模式的一些指导。

我有一个管道分隔文件,我想删除所有第四个单元格为空白的行。每行可以有任意数量的单元格。

到目前为止我的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace EpicRemoveBlankPriceRecords
{
    class Program
    {
        static void Main(string[] args)
        {
            string line;

            // Read the file and display it line by line.
            System.IO.StreamReader inFile = new System.IO.StreamReader("c:\\test\\test.txt");
            System.IO.StreamWriter outFile = new System.IO.StreamWriter("c:\\test\\test_out.txt");
            while ((line = inFile.ReadLine()) != null)
            {
                Match myMatch = Regex.Match(line, @".*\|.*\|.*\|\|.*");
                if (!myMatch.Success)
                {
                    outFile.WriteLine(line);
                }
            }

            inFile.Close();
            outFile.Close();

            //// Suspend the screen.
            //Console.ReadLine();


        }
    }
}

这不起作用。我认为这是因为 RegEx 是“贪婪的”——如果有任何空白单元格,这匹配,因为我没有明确地说“捕获除了管道字符之外的所有内容”。快速搜索一下,我发现我可以在模式中使用 [^\|] 来做到这一点。

所以,如果我将模式更改为:

 ".*[^\|]\|.*[^\|]\|.*[^\|]\|\|.*"

为什么这也不起作用?

猜我有点困惑,任何指针将不胜感激。

谢谢!

【问题讨论】:

  • 你对我来说太快了——我注意到了这一点并进行了相应的编辑。不幸的是,我的模式仍然无法正常工作。谢谢
  • 这里有什么需要使用正则表达式的原因吗?在我看来,像string.IsNullOrEmpty(line.Split('|')[2]) 这样的操作会容易得多。
  • 第 3 项是从 1 还是从 0? =)
  • 感谢@Maslow - 为了澄清,我编辑到第四位
  • @MagnusGrindalBakken 我真的很想了解更多关于正则表达式的信息,但你是对的 - 拆分将是这里最简单的解决方案

标签: c# regex regex-greedy


【解决方案1】:

这里真的需要正则表达式吗?

var lines = File.ReadLines(filename)
           .Where(line => !String.IsNullOrWhiteSpace(line.Split('|')[3]));

File.WriteAllLines(outfile, lines);

【讨论】:

    【解决方案2】:

    这似乎适用于regexpal

    ^[^|]*\|[^|]*\|[^|]*\|\|.*
    
    • ^ 单独表示行首
    • [^|]| 之外的任何字符
    • [^|]* 匹配零个或多个非 | 字符
    • + 可能不适合您的用法,但这意味着至少有一个,但它会发现更多
    • .* 意味着任何东西,并且尽可能多地找到。

    测试数据:

    • abc|123|234||673
    • abc|def||123|456
    • abc|123|234|673||ab

    【讨论】:

    • 抱歉编辑。尽管如此,我们稍后会在文件中捕获空白字段 - 例如。我抓到 abc|123|234|673||ab||
    • 谢谢@Maslow。我已经接受了这个作为答案,因为它可以满足我的需要并且有很好的说明 - 看起来我的错误是我不需要从 [] 中逃脱管道。
    • j.mp/1arsY2T - 更新了更多测试数据的链接,+ 不正确。
    【解决方案3】:

    .*[^\|] 表示零个或多个通配符 (.*) 和一个不是 | 的字符 ([^\|])。

    另外,您需要在[] 中转义|

    Regex.Match 实际上并不匹配,它会搜索,因此您需要在正则表达式的开头(表示字符串的开头)使用^

    因此也不需要结尾的.*

    您需要零个或多个不是| 的字符,如下所示:

    "^[^|]*\|[^|]*\|[^|]*\|\|"
    

    Test.

    为什么".*\|.*\|.*\|\|.*" 不起作用:

    除了以上原因...

    * 变得贪婪并没有太大变化(你可以通过 .*? 让它变得非贪婪/懒惰)。问题是. 也匹配| 并且它回溯,所以.* 将包含尽可能多或尽可能少的| 以匹配字符串(是的,它会尝试包含更多,因为它是贪婪的,但这不会改变它是否找到某些东西,只会改变它找到的东西)。

    您可以使用惰性匹配和possessive quantifiers 一起破解某些东西,但最终会变得更加复杂,更重要的是,我想 C# 不支持这些。

    【讨论】:

    • 如果文件后面有空白单元格,这似乎仍然可以捕获(例如,如果第 5 个单元格是空白的,它会捕获单元格 2、3、4 和 5)
    • @Ekins86 这应该可以,只需将^$ 添加到正则表达式的开头和结尾即可。
    • @Ekins86 似乎Match 不匹配,它会搜索。稍微修改了我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-14
    • 1970-01-01
    • 1970-01-01
    • 2018-03-17
    • 2020-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多