Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/272.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 正则表达式有时给出错误的答案_C#_Regex - Fatal编程技术网

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> ::

我正在尝试匹配国际象棋的符号。我有一个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> ::= <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]