正则表达式:如果有的话,如何排除后面的可能单词

时间:2018-05-20 16:34:30

标签: c# regex

我正在逐行阅读列表并在c#中使用正则表达式来捕获字段:

  

fed line 1:Type:eBook年份:1990标题:这是电子书1 ISBN:15465452页数:100作者:Cendric,Paul

     

馈线2:类型:电影年份:2016标题:这是电影1作者:Pepe Giron; Yamasaki Suzuki长度:4500媒体类型:DVD

string pattern = @"(?:(Type: )(?<type>\w+)) *(?:(Year: )(?<year>\d{4})) *(?:(Title: )(?<title>[^ISBN]*))(?:(ISBN:) *(?<ISBN>\d*))* *(?:(Pages: )(?<pages>\d*))* *(?:(Authors: )(?<author1>[\w ,]*)) *;* *(?<author2>[\w ,]*) *(?:(Length: )(?<length>\d*))* *(?:Media Type: )*(?<discType>[\w ,]*)";

MatchCollection matches = Regex.Matches(line, pattern);

如果换行有“长度:”我想停止捕获作者的姓氏,不包括单词长度。

如果我使用(?:(Length: )(?<length>\d*))*长度被添加到match.Groups["author2"].Value的第二作者的姓氏中。如果我使用(?:(Length: )(?<length>\d*))+,我的第一行没有匹配。

你可以给我指导吗? 谢谢Sergio

2 个答案:

答案 0 :(得分:1)

使用完全正则表达式来处理与您所拥有的格式一样模糊的东西总是一种伤害自己的方式。正如@Kevin所写,您应该查找键并提取值。

我的建议是寻找这些密钥并在它们之前和之后拆分字符串。有一个漂亮,随机工作(他们甚至改变了它在.NET 1.1和.NET 2.0之间的工作),几乎未知的Regex功能,称为Regex.Split()。我们可以尝试使用它: - )

string pattern = @"(?<=^| )(Type: |Year: |Title: |ISBN:|Pages: |Authors: |Length: |Media Type: )";
var rx = new Regex(pattern);
string[] parts = rx.Split(line);

现在parts是一个数组,其中if在一个元素中有一个键,在下一个元素中有值...... Regex.Split可以在数组的开头添加一个空元素

string type = null, title = null, mediaType = null;
int? year, length;
string[] authors = new string[0];


// The parts[0] == string.Empty ? 1 : 0 is caused by the "strangeness" of Regex.Split
// that can add an empty element at the beginning of the string
for (int i = parts[0] == string.Empty ? 1 : 0; i < parts.Length; i += 2)
{
    string key = parts[i].TrimEnd();
    string value = parts[i + 1].Trim();
    Console.WriteLine("[{0}|{1}]", key, value);

    switch (key)
    {
        case "Type:":
            type = value;
            break;
        case "Year:":
            {
                int temp;
                if (int.TryParse(value, out temp))
                {
                    year = temp;
                }
            }
            break;
        case "Title:":
            title = value;
            break;
        case "Authors:":
            {
                authors = value.Split(" ; ");
            }
            break;
        case "Length:":
            {
                int temp;
                if (int.TryParse(value, out temp))
                {
                    length = temp;
                }
            }
            break;
        case "Media Type:":
            mediaType = value;
            break;
    }
}

答案 1 :(得分:1)

毕竟,@ xanathos是对的。从长远来看,一个难以维护且容易出错的过度复杂的正则表达式可能无法很好地为您服务。

但要回答您的问题,您的正则表达式可以使用tempered greedy token *修复,例如在作者的模式中不允许Length:

(?:(?:(?!Length: )[\w ,])*)

*链接描述在贪婪令牌中使用.,但在此处限制允许字符的范围更有用。

可以说,这应该添加到author1author2部分。

最终模式如下:

(?:(Type: )(?<type>\w+)) *(?:(Year: )(?<year>\d{4})) *(?:(Title: )(?<title>[^ISBN]*))(?:(ISBN:) *(?<ISBN>\d*))* *(?:(Pages: )(?<pages>\d*))* *(?:(Authors: )(?<author1>(?:(?:(?!Length: )[\w ,])*) *)) *;* *(?<author2>(?:(?:(?!Length: )[\w ,])*) *)(?:(Length: )(?<length>\d*))* *(?:Media Type: )*(?<discType>[\w ,]*)

Demo