0

好的,我放弃了——是时候向正则表达式专家寻求帮助了。

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

每行数据由逗号分隔的单词组成,每个单词包含a-z,0-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 模式(它有除_and之外-的标点符号,首先)。

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

4

4 回答 4

4

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

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

foo, bar

因此该文本也匹配:

var result = calculate(foo, bar);

你可以看到这是怎么回事。

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

于 2013-06-19T15:57:11.720 回答
1

这是一个更好的模式,它在每​​行中查找 CSV 组,例如XXX,yyy一对多:

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

^ - 每行的开始

( - CSV 匹配组开始

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

,? - 也许是一个逗号

)+ - csv 匹配组的结尾,预期为 1 到许多。

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

于 2013-06-19T16:07:51.230 回答
0

我想这就是你要找的:

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

值得注意的变化是:

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

你的正则表达式的基本结构看起来相当不错,直到|出现并把事情搞砸了。;)

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

于 2013-06-19T17:49:21.763 回答
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;
}
于 2013-06-19T16:02:05.383 回答