>我有一个正则表达式,它匹配表示Excel范围的字符串(加上单个单元格)
^[A-Z]+[1-9][0-9]*(:[A-Z]+[1-9][0-9]*)?(,[A-Z]+[1-9][0-9]*(:[A-Z]+[1-9][0-9]*)?)*$
例如,它匹配以下字符串:
C5:H6,J5:P6,R5:DM6,C15
我问是否有任何方法可以避免模式中的冗余:
C6
由[A-Z]+[1-9][0-9]*
匹配,但也H6
由相同的模式匹配。
同样,J6:P6
与C6:H6
匹配的相同模式匹配。
如果要表达类似"匹配此模式 1 次,或 * 次,但仅在逗号分隔的情况下"之类的内容。
提前感谢!
您可以按如下方式更改正则表达式:
^([A-Z]+[1-9][0-9]*(:[A-Z]+[1-9][0-9]*)?(,(?!$)|$))*$
关键的变化是末尾的这个子表达式:
(,(?!$)|$)
它匹配可选的逗号字符,除非它位于匹配的末尾,在这种情况下,不得有其他字符。这会阻止您匹配以悬挂逗号结尾的序列。
这是关于 ideone 的相应演示。
对于任何系列的范围和单个单元格,请使用正则表达式模式
(?!,)(?:(?:^|,)[A-Z]+(?!0)[0-9]+(?::[A-Z]+(?!0)[0-9]+)?)+
或者,如果您只想匹配以逗号分隔的一系列相同范围(或单个单元格),则
^([A-Z]+(?!0)[0-9]+(?::[A-Z]+(?!0)[0-9]+)?)(,1)*
要删除源代码中的冗余,您可以将重复的组件存储到字符串变量中,并从字符串中构造正则表达式。
像这样:
string cellname = "[A-Z]+[1-9][0-9]*";
string cellrange = cellname + "(:" + cellname + ")?";
Regex pattern = new Regex("^" + cellrange + "(," + cellrange + ")*$")
如果您询问是否有用于分隔符的二进制正则表达式运算符,即您可以为其编写的内容
A op B
并有意为
之A(BA)*
那么恐怕这样的事情并不存在。附录:但是,您可以接近
((^|B)A)+$
这转换为"一个或多个以字符串开头或 B 为前缀的 As"。 在这里,您的 B 将是逗号,您的 As 将是范围。 然后,您可以在范围内使用相同的技术来用冒号分隔单元格。 但是,您将使用(xxx|:)
而不是(^|,)
,其中xxx
扮演单元格开头的角色。 我不确定那会是什么。 你能用吗?
增编2
http://ideone.com/L3RNEr 的解决方案 - 基于我的最后一条评论。
using System;
using System.Text.RegularExpressions;
public class Test
{
public static void Main()
{
Regex rx = new Regex("^([A-Z]+[1-9][0-9]*(:[A-Z]+[1-9][0-9]*)?($|,(?!$)))*$");
Console.WriteLine(rx.IsMatch("C5:H6"));
Console.WriteLine(rx.IsMatch("C5"));
Console.WriteLine(rx.IsMatch("C5:H6,J5:P6,R5:DM6,C15"));
Console.WriteLine(rx.IsMatch("C5:H6,J5:P6,R5:DM6,C15,"));
Console.WriteLine(rx.IsMatch("C5:H6J5:P6,R5:DM6,C15"));
Console.WriteLine(rx.IsMatch(",C5:H6:J5:P6,R5:DM6,C15"));
}
}
如果你想在一个表达式中测试整个字符串的有效范围,如果你不介意在测试字符串前面加上逗号,你可以使用这个正则表达式(像这样:,C5:H6,J5:P6,R5:DM6,C15):
^(?:,[A-Z]+[1-9][0-9]*(?::[A-Z]+[1-9][0-9]*)?)*$
如果无法更改测试字符串,可以改用以下内容:
^(?:(?:^|,)[A-Z]+[1-9][0-9]*(?::[A-Z]+[1-9][0-9]*)?)*$