正则表达式没有给我预期的结果

时间:2013-06-19 15:52:53

标签: c# regex

好吧,我放弃了时间来请求正则表达式大师们寻求帮助。

我正在尝试验证CSV文件内容,只是为了查看它是否与预期的有效CSV数据一样。我不是要验证所有可能的CSV表单,只是它“看起来像”CSV数据,而不是二进制数据,代码文件或其他任何内容。

每行数据都包含以逗号分隔的单词,每个单词包含a-z0-9和少量标点字符,即-_。文件中可能有几行。而已。

这是我的简单代码:

const string dataWord = @"[a-z0-9_\-]+";
const string dataLine = "("+dataWord+@"\s*,\s*)*"+dataWord;
const string csvDataFormat = "("+dataLine+") |  (("+dataLine+@"\r\n)*"+dataLine +")";

Regex validCSVDataPattern = new Regex(csvDataFormat, RegexOptions.IgnoreCase);
protected override bool IsCorrectDataFormat(string fileContents)
{
    return validCSVDataPattern.IsMatch(fileContents);
}

这给了我一个正则表达式

(([a-z0-9_\-]+\s*,\s*)*[a-z0-9_\-]+) |  ((([a-z0-9_\-]+\s*,\s*)*[a-z0-9_\-]+\r\n)*([a-z0-9_\-]+\s*,\s*)*[a-z0-9_\-]+)

但是,如果我用一块C#代码来表示它,那么正则表达式解析器就说它是匹配的。那个怎么样? C#代码看起来与我的CSV模式不同(它有_-以外的标点符号作为开头)。

有人能指出我明显的错误吗?让我再说一遍 - 我不是要验证所有可能的CSV表单,只是我的简单子集。

4 个答案:

答案 0 :(得分:4)

您的正则表达式缺少^(行首)和$(行尾)锚点。这意味着它将匹配包含的任何文本表达式所描述的内容,即使文本包含其他完全不相关的部分。

例如,此文本与表达式匹配:

foo, bar

因此本文也匹配:

var result = calculate(foo, bar);

你可以看到它的发展方向。

在开头添加^,在$结尾添加csvDataFormat以获得您期望的行为。

答案 1 :(得分:1)

以下是一个更好的模式,可以查找每个行中一对多的CSV组,例如XXX,yyy

^([\w\s_\-]*,?)+$

^ - 每行开头

( - CSV匹配组开始

[\w\s_\-]* - 每个CSV中的有效字符\w (a-zA-Z0-9)_以及-

,? - 也许是逗号

)+ - csv匹配组的结尾,预期会有1到多个。

这将为基本CSV结构逐行验证整个文件,并允许空,,个情况。

答案 2 :(得分:0)

我想出了这个正则表达式:

^([a-z0-9_\-]+)(\s*)(,\s*[a-z0-9_\-]+)*$

测试

asbc_- ,   khkhkjh,    lkjlkjlkj_-,     j : PASS
asbc,                                     : FAIL
asbc_-,khkhkjh,lkjlkjlk909j_-,j           : PASS

如果您想匹配,,,之类的空行,或者某些值为空,abcd,,,请使用

^([a-z0-9_\-]*)(\s*)(,\s*[a-z0-9_\-]*)*$

遍历所有行以查看文件是否正常:

const string dataLine = "^([a-z0-9_\-]+)(\s*)(,\s*[a-z0-9_\-]+)*$";
Regex validCSVDataPattern = new Regex(csvDataFormat, RegexOptions.IgnoreCase);
protected override bool IsCorrectDataFormat(string fileContents)
{
    string[] lines = fileContents.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);

    foreach (var line in lines)
    {
        if (!validCSVDataPattern.IsMatch(line))
        return false;
    }

    return true;
}

答案 3 :(得分:0)

我认为这就是你要找的东西:

@"(?in)^[a-z0-9_-]+( *, *[a-z0-9_-]+)*([\r\n]+[a-z0-9_-]+( *, *[a-z0-9_-]+)*)*$"

值得注意的变化是:

  • 添加了锚点^$,因为没有它们的正则表达式毫无意义
  • 删除了空格(必须与文字空格相匹配,我认为这不是你想要的)
  • 在每个\s出现的\s*替换为文字空格(因为\s可以匹配任何空格字符,并且您只想匹配这些点中的实际空格)

你的正则表达式的基本结构看起来非常好,直到|出现并且搞砸了。 ;)

p.s。,如果您想知道,(?in)是一个设置IgnoreCaseExplicitCapture模式的内联修饰符。