好吧,我放弃了时间来请求正则表达式大师们寻求帮助。
我正在尝试验证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模式不同(它有_
和-
以外的标点符号作为开头)。
有人能指出我明显的错误吗?让我再说一遍 - 我不是要验证所有可能的CSV表单,只是我的简单子集。
答案 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)
是一个设置IgnoreCase
和ExplicitCapture
模式的内联修饰符。