C# 正则表达式有时给出错误的答案
我正在尝试匹配国际象棋的符号。我有一个C#正则表达式,如下所示:C# 正则表达式有时给出错误的答案,c#,regex,C#,Regex,我正在尝试匹配国际象棋的符号。我有一个C#正则表达式,如下所示: "(?:[PNBRQK]?[a-h]?[1-8]?x?[a-h][1-8](?:\=[PNBRQK])?|O(-?O){1,2})[\+#]?(\s*[\!\?]+)?"; [我不介意用C#YACC lexer表示短代数符号(SAN),但我现在正在使用正则表达式:] <move> ::= <move number><move descriptor> <move number> ::
"(?:[PNBRQK]?[a-h]?[1-8]?x?[a-h][1-8](?:\=[PNBRQK])?|O(-?O){1,2})[\+#]?(\s*[\!\?]+)?";
[我不介意用C#YACC lexer表示短代数符号(SAN),但我现在正在使用正则表达式:]
<move> ::= <move number><move descriptor>
<move number> ::= <digit>[<digit>...]{'.' | '...'}
<move descriptor> ::= <from square><to square>[<promoted to>]
<square> ::= <file letter><rank number>
<file letter> ::= 'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'
<rank number> ::= '1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'
<promoted to> ::= 'q'|'r'|'b'|'n'
<Piece symbol> ::= 'P' | 'N' | 'B' | 'R' | 'Q' | 'K'
<SAN move descriptor piece moves> ::= <Piece symbol>[<from file>|<from rank>|<from
square>]['x']<to square>
<SAN move descriptor pawn captures> ::= <from file>[<from rank>] 'x' <to square>[<promoted to>]
<SAN move descriptor pawn push> ::= <to square>[<promoted to>]
结果应该是(代码在移动后添加句点,但不是必需的):
请注意,第一步和第五步是错误的,因为它同时匹配白人和黑人的动作
我的正则表达式做了什么修改,使它能够工作,使它始终只匹配单面移动
这是密码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
namespace ChessPGNParserConsoleApplication
{
class Program
{
static void Main(string[] args)
{
string regexStr = @"(?:[PNBRQK]|[a-h][1-8]?x)?[a-h][1-8]|(O(-?O){1,2})[\+#]?(\s*[\!\?]+)?";
//string regexStr = @"(?:[PNBRQK]|[a-h][1-8]?x)?[a-h][1-8](?:\=[PNBRQK])?(O(-?O){1,2})[\+#]?(\s*[\!\?]+)?";
//string regexStr = @"(?:[PNBRQK]?[a-h]?[1-8]?x?[a-h][1-8](?:\=[PNBRQK])?|O(-?O){1,2})[\+#]?(\s*[\!\?]+)?";
//string regexStr = @"(?:[PNBRQK]?[a-h]?[1-8]?x?[a-h][1-8](?:\=[PNBRQK])?|O(-?O){1,2})[\+#]?(\s*[\!\?]+)?";
//string regexStr = @"(?:[PNBRQK]?[a-h]?[1-8]?x?[a-h][1-8])";
string startsDigitRegexStr = @"^\d*";
Regex regexpr = new Regex(regexStr);
Regex regexprDigit = new Regex(startsDigitRegexStr);
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader(@"C:\Users\idf\Documents\My Chess Database\chessgame.txt");
string replacement = "";
int moveNumber = 1;
string line;
while (null != (line = file.ReadLine()))
{
MatchCollection mcDigit = regexprDigit.Matches(line);
foreach (Match m in mcDigit)
{
line = regexprDigit.Replace(line, replacement);
//Console.WriteLine(m);
}
//Console.WriteLine(line);
MatchCollection mc = regexpr.Matches(line);
int twoMoves = 0;
Console.Write(moveNumber.ToString() + ". ");
foreach (Match m in mc)
{
Console.Write(m + " ");
if(1 == twoMoves++)
Console.WriteLine();
}
moveNumber++;
}
Console.ReadLine();
}
}
}
未经测试,但请尝试以下方法:
(?:[PNBRQK]|[a-h][1-8]?x)?[a-h][1-8](?:\=[PNBRQK])?|O(-?O){1,2})[\+#]?(\s*[\!\?]+)?
理由:
[PNBRQK]|[a-h][1-8]?x
最多匹配一次[PNBRQK]x
或[a-h]x
或[a-h][1-8]x
,但需要前缀末尾的x
。这意味着e4d5
(e4
)的前半部分将与该组的[a-h][1-8]
部分不匹配,因为我们需要结尾x
字符
[a-h][1-8]
匹配不带前缀的实际移动的内容。这将匹配e4
,并且只匹配e4
,将d5
从第一行开始解释为下一步
原始正则表达式在
x
字符之前使用了?
运算符,因此[a-h]?[1-8]?x
匹配e4
,然后[a-h][1-8]
匹配d5
,导致第一轮的输出不正确。最后,我不知道[a-h][1-8]
之后的东西是否有必要,但我把它放在那里了,因为我不知道国际象棋记谱法的细节。对于任何实际用途,你都需要长记谱法(例如,解决Nb1d2和Nf3d2之间的歧义)
但为什么不重新使用:
请将您的表达分解为更小的部分,以供我们理解(以及您将来的理解,如果您近期需要阅读或记录)。 您可以让正则表达式生成器进行智能扫描表优化 您还可以构建一些单元测试来测试您的正则表达式扫描器 您可以在以后“或”显示结果,而不必担心重复太多
就像在下面的链接中一样:我无法编译字符串regexStr=@“(?:(?:[PNBRQK]|[a-h][1-8]?)x)?[a-h][1-8](?:\=[PNBRQK])?\O(--O{1,2})[\+\\+];Regex regexpr=新的Regex(regexStr);例外是“太多”,这很奇怪,因为它们匹配。我删除了内括号,在二读时,它们可能不是必需的。我已经包括了整个游戏。所有提出的解决方案都解决了一个问题,但引入了其他问题。结果应该是什么?并不是所有人每天都看象棋。当我阅读以完成比赛时,我认为你们无论如何都应该使用单独的扫描仪。您将有一些额外的验证点,可以轻松地检查典当移动cxe6(这在您的regexp中是有效的,但在实践中是无效的)。另外,Rooks Rfd8和kNight(Nbd2)的模糊性解决可能会变得困难。另外,从最初的regexp中,您还可以尝试同时匹配移动和行尾字符($),因此lexer知道它应该在同一移动中找到两个“”。
[PNBRQK]|[a-h][1-8]?x
[a-h][1-8]