简体   繁体   English

如何解析一组国际象棋动作的字符串并单独存储每个动作 C++

[英]How to parse a string of a set of chess moves and store each move individually C++

So I am reading a.txt file that has many sets of chess moves.所以我正在阅读一个包含多组国际象棋动作的 .txt 文件。 I am able to read data from the file and insert the line into a string.我能够从文件中读取数据并将该行插入到字符串中。

An example single chess move can look like this:一个示例单步棋可能如下所示:

1. e4 e5

I have written the following function to parse a single chess move:我编写了以下 function 来解析单个国际象棋移动:

void parseSingleChessMove(string move)
  {
    this->moveNumber = stoi(move.substr(0, move.find("."))); 
    this->move[0] = move.substr(move.find_first_of(" ")+1, move.find_last_of(" ")-move.find_first_of(" ")-1);
    this->move[1] = move.substr(move.find_last_of(" ")+1);
  }

I am parsing the string and storing it within a self-defined Move Class hence the use of the 'this' operator.我正在解析字符串并将其存储在自定义的Move Class中,因此使用了“this”运算符。 This function works perfectly and stores each field of a single chess move.这个 function 完美地工作并存储单个国际象棋移动的每个字段。 move[0] stores the first move and move[1] stores the second move, while the moveNumber data member stores the number the move was played at. move[0] 存储第一个移动,move[1] 存储第二个移动,而 moveNumber 数据成员存储移动的数字。

I am creating an array of the Move Class in order to store every single move of a chess match in order.我正在创建一个 Move Class 数组,以便按顺序存储国际象棋比赛的每一步。 However, a complete set of chess moves can look something like this:然而,一套完整的国际象棋走法可能看起来像这样:

1. Nf3 Nf6 2. c4 c6 3. g3 g6 4. b3 Bg7 5. Bb2 O-O 6. Bg2 d5 7. O-O Bf5 8. d3
Nbd7 9. Nd4 e6 10. h3 h5

I am having a hard time trying to figure out how to store each of these individual moves in the array of Move Class from a string of a set of chess moves.我很难弄清楚如何将这些单独的移动中的每一个存储在一系列国际象棋移动中的移动 Class 数组中。

The main issue is reading the string only until a move number is found.主要问题是仅在找到移动编号之前读取字符串。 I then need to obtain a substring for a move (something like 4. b3 Bg7 and then parsing this single chess move using the above function so that I can store moveNumber=4, move[0]="b3" and move[1]="Bg7" and finally storing it into the respective index of array type Move Class. And then repeating this until all moves are stored one by one and we reach the end of the string.然后我需要获得一个 substring 进行移动(类似于4. b3 Bg7 ,然后使用上面的 function 解析这个单一的国际象棋移动,以便我可以存储 moveNumber=4、move[0]="b3" 和 move[1] ="Bg7" 最后将其存储到数组类型 Move Class 的相应索引中。然后重复此操作,直到所有移动都被一一存储,我们到达字符串的末尾。

EDIT: This is my class definition:编辑:这是我的 class 定义:

class MoveNode {
  public:
    array<string, 2> move; 
    int moveNumber; 

    void parseSingleChessMove(string move)
    {
      this->moveNumber = stoi(move.substr(0, move.find("."))); 
      this->move[0] = move.substr(move.find_first_of(" ")+1, move.find_last_of(" ")-move.find_first_of(" ")-1);
      this->move[1] = move.substr(move.find_last_of(" ")+1);
    }
}

I am storing all of the moves in this array: MoveNode *setofMoves = new MoveNode[totalMoves];我将所有的移动存储在这个数组中: MoveNode *setofMoves = new MoveNode[totalMoves];

You could use regular expressions for this:您可以为此使用正则表达式:

  • The pattern to search repeatedly for would be: (\d+)\.重复搜索的模式是: (\d+)\. a number of one or more digits (which we are going to capture), followed by a dot;一个或多个数字(我们将要捕获),后跟一个点; then \s+([^\s]+) one or more whitespaces, followed by one or more non-whitespaces (and we capture these latter);然后\s+([^\s]+)一个或多个空格,然后是一个或多个非空格(我们捕获后者); we repeat these pattern twice, once for each move;我们重复这些模式两次,每次移动一次; finally \s+ , again one or more whitespaces.最后\s+ ,又是一个或多个空格。
    We use std::regex to store the pattern, wrapping it all within R"()" , so that we can write the raw expression.我们使用std::regex来存储模式,将其全部包装在R"()"中,以便我们可以编写原始表达式。
  • The while loop does a few things: it searches the next match with regex_search , extracts the captured groups (move number, move 0 and move 1), and updates the input line, so that the next search will start where the current one finished. while循环做了一些事情:它使用regex_search搜索下一个匹配项,提取捕获的组(移动编号、移动 0 和移动 1),并更新输入行,以便下一次搜索将从当前搜索完成的位置开始。
    matches is an array whose first element, matches[0] , is the part of line matching the whole pattern, and the next elements correspond to the pattern's captured groups. matches是一个数组,其第一个元素matches[0]是匹配整个模式的line的一部分,下一个元素对应于模式的捕获组。

[Demo] [演示]

#include <iostream>  // cout
#include <regex>  // regex_search, smatch

int main() {
    std::string line{"1. Nf3 Nf6 2. c4 c6 3. g3 g6 4. b3 Bg7 5. Bb2 O-O 6. Bg2 d5 7. O-O Bf5 8. d3 Nbd7 9. Nd4 e6 10. h3 h5"};
    std::regex pattern{R"((\d+)\.\s+([^\s]+)\s+([^\s]+)\s+)"};
    std::smatch matches{};
    while (std::regex_search(line, matches, pattern))
    {
        std::cout
            << "moveNum=" << matches[1] << ", "
            << "move[0]=" << matches[2] << ", "
            << "move[1]=" << matches[3] << "\n";
        line = matches.suffix();
    }
}

@rturrado showcased how you could do this with regex, however I would hesitate to do it like that, since std::regex is heavy, and requires a lot of knowledge regarding regex to use it effectively. @rturrado展示了如何使用正则表达式来做到这一点,但是我会犹豫这样做,因为std::regex很重,并且需要大量关于正则表达式的知识才能有效地使用它。 Instead, I think it's easier to accomplish it with istream and operator>> .相反,我认为使用istreamoperator>>更容易完成它。

void parse_moves(std::istream& input)
{
    int move_number;
    char dot;
    std::string move_fisrt, move_second;
    int index = 0;
    while(input >> move_number >> dot >> move_first >> move_second)
    {
        setofMoves[index] = MoveNode{{move_first, move_second}, move_number};
        ++index;
    }
}

Here while(is >>...) will keep parsing the text as long it's following the pattern.这里while(is >>...)将继续解析文本,只要它遵循模式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM