C# 可以在字符类中使用.NET RegEx backreference来排除以前匹配的字符吗?
我试图完成的任务是给定一个输入模式,例如123421,通过字典查找符合给定模式的单词。在我的代码中,我尝试获取给定字符串并将其转换为正则表达式,如下所示: (?)(?)(?)(\k)(\k)(?)(\k)(\k)(\k) (在任何人开始抨击点的使用之前,因为我的输入是一个只有真实单词的字典文件,所以我留下点是为了有一个更清晰的表达式,而不是指定字符的范围。) 这个表达式设法找到了正确的单词,但有一个缺陷。使用诸如123456这样的模式,问题变得非常明显。我的算法生成以下正则表达式: (?)(?)(?)(?)(?)(?) 这是错误的,因为它将匹配任何6个字符的字符串,而没有考虑到每个组都不应该匹配以前的组已经匹配的任何字符。换句话说,它没有考虑到每个字母是不同的;没有重复 因此,我尝试在互联网上查找语法,以排除字符类中的命名组,即 [^\1](不工作)、[^(\k)](不工作)、[^${1}](不工作)等等 在.NET文档中,它显示\p{name}在字符类中是有效的语法,但我尝试了[^\p{1}],但也没有成功 所以,问题仍然存在……是否有可能将命名组排除在进一步匹配之外?或者,我该如何解决这个问题 更新 根据我在这里得到的回复发布我的最终解决方案。此方法获取一个字符串,指定要查找的模式,并将其转换为正则表达式,然后将其应用于字典,并查找符合该模式的所有单词C# 可以在字符类中使用.NET RegEx backreference来排除以前匹配的字符吗?,c#,regex,C#,Regex,我试图完成的任务是给定一个输入模式,例如123421,通过字典查找符合给定模式的单词。在我的代码中,我尝试获取给定字符串并将其转换为正则表达式,如下所示: (?)(?)(?)(\k)(\k)(?)(\k)(\k)(\k) (在任何人开始抨击点的使用之前,因为我的输入是一个只有真实单词的字典文件,所以我留下点是为了有一个更清晰的表达式,而不是指定字符的范围。) 这个表达式设法找到了正确的单词,但有一个缺陷。使用诸如123456这样的模式,问题变得非常明显。我的算法生成以下正则表达式: (?)(?)
string pattern = "12332421";
private void CreateRegEx()
{
string regex = "^";
for( int i = 0; i < pattern.Length; i++ )
{
char c = pattern[i];
if (char.IsDigit(c))
{
if (isUnique(c))
{
regex += "(.)(?!.*\\" + c + ")(?<!\\" + c + ".+)";
}
else
{
if (isFirstOccurrence(c, i))
regex += "(.)";
else
regex += "\\" + c;
}
}
else if (char.IsLetter(c))
regex += c + "";
else if (c == '?')
regex += ".";
}
regex += "$";
reg = new Regex(regex, RegexOptions.IgnoreCase);
}
private bool isUnique(char c)
{
return pattern.IndexOf(c) == pattern.LastIndexOf(c);
}
private bool isFirstOccurrence(char c, int i)
{
return pattern.IndexOf(c) == i;
}
public List<string> GetMatches()
{
return dictionary.FindAll(x => reg.IsMatch(x));
}
string pattern=“12332421”;
私有void CreateRegEx()
{
字符串regex=“^”;
for(int i=0;i regex+=“()(?!.\\\\“+c+”(答案是:不。您不能在.NET正则表达式的字符类中使用反向引用。很抱歉。请参阅下面针对您的情况的解决方法
“它显示\p{name}是有效的语法
在字符类中”
是的。但是.NET文档没有说名称将从反向引用中解释。它必须是unicode文本类字符串
“换句话说,它不考虑
说明每个字母都是不同的;
没有重复。”
我理解这意味着匹配所有efax
,并且只匹配f
和x
中的efex
。换句话说,匹配唯一字符,不匹配重复的字符
解决方案
我对您的问题的理解如下:匹配字符串中所有在其前后不重复的唯一单词(子表达式、字符)。您应该使用的基本正则表达式如下:
(subexpr)(?!.*\1)(?<!\1.+)
您可以将其概括为匹配字符串中的每个唯一字母:
(.)(?!.*\1)(?<!\1.+)
应用溶液
一个单词有一个模式。魅魔是1 2 3 3 2 2 1。过去是1 2 3 4。根据这个模式,正则表达式应该匹配具有相同模式的单词:单词长度相同,相同字母在相同位置重复:过去和咆哮具有相同的模式。LOOK和HEEL具有相同的模式,但不是这里
按照前面的解决方案,我们通常会根据您的问题领域,通过遵守以下规则来调整该解决方案:
唯一的字母由(?!.*\X)(?)表示
重复的字母由(.)表示
重复发生的位置由\X
表示(无括号!)
\X
表示带图案编号的反向引用
示例:
# SUCCUBUS is 1 2 3 3 2 4 2 1 (only 4 is unique)
(.) # nr 1 in pattern
(.) # nr 2 in pattern
(.) # nr 3 in pattern
\3 # repeat 3
\2 # repeat 2
(.)(?!.*\4)(?<!\4.+) # nr 4 UNIQUE!
\2 # repeat 2
\1 # repeat 1
# PAST (all unique: 1 2 3 4)
(.)(?!.*\1)(?<!\1.+) # nr 1 in pattern
(.)(?!.*\2)(?<!\2.+) # nr 2 in pattern
(.)(?!.*\3)(?<!\3.+) # nr 3 in pattern
(.)(?!.*\4)(?<!\4.+) # nr 4 in pattern
#女妖是12 3 2 1(只有4个是唯一的)
()#图案中的编号1
()#图案中有2个
()#图案中有3个
\3#重复3次
\2#重复2次
(.)(?!.*\4)(?
这种模式应该可以很容易地自动化到您当前的系统中
测试此正则表达式和其他正则表达式(只需复制并粘贴我的正则表达式)的一个很好的方法是
更新:删除了以前不相关的更新说明
更新1:在另一个解决方案中的注释中,您说您希望能够匹配符合模式的子字符串。当然,这对负向前/向后展望提出了挑战:现在,他们查看整个字符串。将*
和+
替换为exp的相对长度在这个地方,过去的位置3变成了(?!{1}\3)(?位置4变成(?!{2}\3)(?)
更新2:同样,如果需要唯一,可以通过删除第一个表达式中的回顾和最后一个表达式中的展望来进行轻微优化:位置1变为()(?!{3}\3)
,位置4变为()(?为了做到这一点,您可以在匹配新组之前使用消极前瞻
我将使用更通用的PCRE表示法:
(.)((?!\1).)((?!\1|\2).)\3\2((?!\1\2\3).)\2\1
上面的正则表达式将匹配字符串12332421
,但不匹配12112421
或11111111
简短的解释:
(.) // match any character (except line breaks) and store it in group 1
( // open group 2
(?!\1) // if looking ahead group 1 cannot be seen,
. // match any character (except line breaks)
) // close group 2
( // open group 3
(?!\1|\2) // if looking ahead group 1 or 2 cannot be seen,
. // match any character (except line breaks)
) // close group 3
\3 // back referencing group 3
\2 // back referencing group 2
( // open group 4
(?!\1\2\3) // if looking ahead group 1, 2 or 3 cannot be seen,
. // match any character (except line breaks)
) // close group 4
\2 // back referencing group 2
\1 // back referencing group 1
当然,你真的不需要分组4,因为你还没有回来
你可能会同意我的看法,正则表达式并不是进行这种匹配的最佳工具
编辑:
我不知道如何构建这些正则表达式,但我无法想象它会比这个简单地接受模式、目标字符串和测试的小方法更简单
(.)((?!\1).)((?!\1|\2).)\3\2((?!\1\2\3).)\2\1
(.) // match any character (except line breaks) and store it in group 1
( // open group 2
(?!\1) // if looking ahead group 1 cannot be seen,
. // match any character (except line breaks)
) // close group 2
( // open group 3
(?!\1|\2) // if looking ahead group 1 or 2 cannot be seen,
. // match any character (except line breaks)
) // close group 3
\3 // back referencing group 3
\2 // back referencing group 2
( // open group 4
(?!\1\2\3) // if looking ahead group 1, 2 or 3 cannot be seen,
. // match any character (except line breaks)
) // close group 4
\2 // back referencing group 2
\1 // back referencing group 1
public class Test {
public static boolean matchesPattern(String text, String pattern) {
if(text.length() != pattern.length()) return false;
Map<Character, Character> mappings = new HashMap<Character, Character>();
for(int index = 0; index < pattern.length(); index++) {
Character patternChar = pattern.charAt(index);
Character textChar = text.charAt(index);
if(mappings.containsKey(patternChar)) {
if(mappings.get(patternChar) != textChar) return false;
}
else {
if(mappings.values().contains(textChar)) return false;
mappings.put(patternChar, textChar);
}
}
return true;
}
public static void main(String[] args) {
String pattern = "abccbdba";
String[] tests = {"12332421", "12112421", "11111111"};
for(String t : tests) {
System.out.println(t+" -> "+matchesPattern(t, pattern));
}
}
}
12332421 -> true
12112421 -> false
11111111 -> false