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

本文关键字:结果 正则表达式 | 更新日期: 2023-09-27 18:19:00

好吧,我放弃了 - 是时候向正则表达式大师寻求帮助了。

我正在尝试验证 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 表单,只是我的简单子集。

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

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

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

foo, bar

因此,此文本也匹配:

var result = calculate(foo, bar);

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

csvDataFormat开头添加^,在末尾添加$,以获得所需的行为。

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

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

^ - 每行的开头

( - CSV 匹配组开始

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

,? - 也许是逗号

)+ - csv 匹配组结束,其中 1 比许多预期。

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

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

^([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;
}

我认为这就是你要找的:

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

值得注意的变化是:

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

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

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