需要正则表达式来匹配用户生成的模式

本文关键字:模式 用户 正则表达式 | 更新日期: 2023-09-27 18:20:06

我有一个用C#(3.5框架)编写的ASP.NET应用程序,用户向我提供了我们制定规则的模式列表。我可以编写代码来手动解释每个模式,但我更喜欢找到一种使用正则表达式(或者任何方法)来处理它们的方法,这样我就可以允许用户在未来创建更多的模式(当然要遵循一些准则)。

我会尽我最大的努力展示我正在努力做的事情。我真的很感谢你的帮助。

以下是一些模式:

模式1:要素1:CxxxxRxxxx元素2:CxxxxRzzzz结果:铲斗1

模式2:元素1:CxxxxRxxxx
要素2:CxxxxRxxxx结果:铲斗2

模式3:要素1:PCxxxxxxxx
元素2:PCzzzzzzzz结果:铲斗3

模式4:要素1:PCxxxxxxxx
元素2:UxxxxRxxxx结果:铲斗4

以下是它们的含义以及我需要如何处理它们。对于初学者来说,所有元素的长度总是10个字符。每个模式的字母字符都是不变的。X和Z可以是数字或字母。图案中X和Z的含义是这两个元素的其他部分是否匹配。

例如,我的输入数据是"C1234R5678"作为元素1,"C1234R9999"作为元素2。在这种情况下,结果将是"Bucket 1",因为这与为该条件定义的模式匹配("C"之后的数字匹配,但"R"之后的号码不匹配)。

在另一个例子中,我的输入数据是"C1234R5678"作为元素1,"C1234R5 678"用于元素2。在这种情况下,结果将是"Bucket 2",因为这与为该条件定义的模式相匹配("C"匹配后的数字以及"R"匹配之后的数字)。

在另一个示例中,我的输入数据是元素1的"PC12345678"和元素2的"PC87654321"。在这种情况下,结果将是"Bucket 3",因为这与为此条件定义的模式相匹配("PC"后面的数字不匹配)。

在最后一个示例中,我的输入数据是元素1的"PC12345678"和元素2的"U1234R5678"。在这种情况下,结果将是"Bucket 4",因为这与为该条件定义的模式相匹配("PC"之后的4个数字与U之后的4位数字相匹配,PC元素的最后4位数字与元素2的R之后的4位数相匹配)。

正如你所看到的,模式可能会有所不同,因为有时你会在一个字母后面识别4个数字,或者在一个单词后面识别一整列数字。

谢谢你抽出时间。

需要正则表达式来匹配用户生成的模式

一种方法是连接元素(可能有一个不能出现在元素中的分隔符),这样每个元素都可以由一个正则表达式匹配。使用捕获和反向引用可以强制后面的子字符串与前面的子字符串匹配。使用负lookahead来确保子字符串与先前的子字符串不匹配;否则,您将不得不依赖于检查模式的顺序来确保模式正确匹配(在示例中,您必须先检查bucket 2,然后再检查bucket 1)。使用波浪形括号限定符来匹配特定数量的字符。

/C(.{4})R'1-C'1R(?!'1).{4}/ -> bucket 1
/C(.{4})R'1-C'1R'1/         -> bucket 2
/PC(.{8})-PC(?!'1).{8}/     -> bucket 3
/PC(.{4})(.{4})-U'1R'2/     -> bucket 4

您可以将部分限制为字母数字字符([A-Za-z'd])或标识符字符('w,相当于'[A-Za-z''d]'),而不是"任何"字符(点)。

将映射存储在列表中,然后在确定要使用哪个bucket时对列表进行迭代。模式和bucket之间的其他映射可以附加到列表中。

当然,这需要您的用户能够编写正则表达式,尽管您可以想出一种更简单的语言来翻译成正则表达式。例如,您可以让用户只指定"{n}"answers"''k",其中前者意味着匹配不应该匹配任何先前组的许多字符,而后者意味着匹配第k个"{n}"。要转换为正则表达式,请将每个"{n}"替换为"(.{n})"(或"(''w{n)"),并在k=1到n-1时加前缀"(?!''k)"。使用C#排序,替换可以指定为:

(1..n-1).sum(k => "(?!''" + k + ")") + "(''w{"+n+"})"

您可以执行以下操作:

For each (Element1,Element2) pair:
    match Element1,Element2 on "(x+|z+)" -> matches1,matches2
    for (i=0;i<min(matches1,matches2);i++) {
        replace 'x+' by '([A-Za-z0-9]{matches1[i].Length})'
        // note: need the brackets here to act as capturing brackets
        // so that backreferences can be used!
        if matches2[i] is 'xxxxx':
            replace 'x+' by '(?!'i)[A-Za-z0--9]{matches2[i].Length}'
        else if matches2[i] is 'zzzzz':
            replace 'z+' by ''i'
    }
    Then replace miscellaneous leftover 'xxxx' by '[A-Za-z0-9]{lengthofmatch}'.
    Then join the new Element1 and Element2 by a delimiter e.g. '-'

这将构造一堆字符串,如:

//Pattern 1
C([A-Za-z0-9]{4})R([A-Za-z0-9]{4})-C(?!'1)[A-Za-z0-9]{4}R'2
//Pattern 2
C([A-Za-z0-9]{4})R([A-Za-z0-9]{4})-C(?!'1)[A-Za-z0-9]{4}R(?!'2)[A-Za-z0-9]{4}
//Pattern 3
PC([A-Za-z0-9]{8})-PC'1
//Pattern 4
PC([A-Za-z0-9]{8})-U(?!'1)[A-Za-z0-9]{4}R[A-Za-z0-9]{4}

然后,对于每个输入数据,附加由'-(例如"C1234R5678-C1234R9999")分隔的Element1和Element2,并根据每个模式进行匹配,并在第一次匹配时停止。