如何解析一组国际象棋动作的字符串并单独存储每个动作 C++
How to parse a string of a set of chess moves and store each move individually C++
所以我正在读取一个 .txt 文件,其中包含多组国际象棋走法。我能够从文件中读取数据并将该行插入到字符串中。
单个国际象棋走法示例如下所示:
1. e4 e5
我编写了以下函数来解析单个棋步:
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);
}
我正在解析字符串并将其存储在自定义的 Move Class 中,因此使用 'this' 运算符。此功能完美运行并存储单个国际象棋移动的每个字段。 move[0] 存储第一个着法,move[1] 存储第二个着法,而 moveNumber 数据成员存储着法的编号。
我正在创建一个 Move Class 数组,以便按顺序存储国际象棋比赛的每一步。然而,一套完整的国际象棋走法可能看起来像这样:
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
我很难弄清楚如何从一组国际象棋动作中将这些单独的动作存储在 Move Class 数组中。
主要问题是只读取字符串直到找到移动编号。然后我需要获得一个移动的子字符串(类似于 4. b3 Bg7
然后使用上述函数解析这个单一的国际象棋移动以便我可以存储 moveNumber=4、move[0]="b3" 和 move[1 ]="Bg7" 最后存储到数组类型 Move Class 的相应索引中。然后重复此操作,直到所有移动都一一存储,我们到达字符串的末尾。
编辑:这是我的 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);
}
}
我将所有动作存储在这个数组中:
MoveNode *setofMoves = new MoveNode[totalMoves];
您可以为此使用正则表达式:
- 重复搜索的模式是:
(\d+)\.
一个或多个数字(我们要捕获,因此使用括号),后跟一个点;然后 \s+([^\s]+)
一个或多个空格,然后是一个或多个非空格(我们捕获后者);我们重复这种模式两次,每次移动一次;最后 (:?\s+|$)
,一个或多个空格 \s+
或 |
表达式的末尾 $
因为输入行可能以第二步结束(我们不捕获这个组 (:?)
).
我们使用 std::regex
来存储模式,将其全部包装在 R"()"
中,以便我们可以编写原始表达式。
while
循环做了一些事情:它搜索与 regex_search
的下一个匹配,提取捕获的组(移动编号,移动 0 和移动 1),并更新输入行,这样下一次搜索将从当前搜索结束的地方开始。
matches
是一个数组,其第一个元素 matches[0]
是 line
匹配整个模式的部分,下一个元素对应于模式的捕获组。
#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();
}
}
// Outputs:
// moveNum=1, move[0]=Nf3, move[1]=Nf6
// moveNum=2, move[0]=c4, move[1]=c6
// moveNum=3, move[0]=g3, move[1]=g6
// moveNum=4, move[0]=b3, move[1]=Bg7
// moveNum=5, move[0]=Bb2, move[1]=O-O
// moveNum=6, move[0]=Bg2, move[1]=d5
// moveNum=7, move[0]=O-O, move[1]=Bf5
// moveNum=8, move[0]=d3, move[1]=Nbd7
// moveNum=9, move[0]=Nd4, move[1]=e6
// moveNum=10, move[0]=h3, move[1]=h5
@rturrado 展示了如何使用正则表达式做到这一点,但是我会犹豫这样做,因为 std::regex
很重,需要很多有关正则表达式的知识以有效地使用它。相反,我认为使用 istream
和 operator>>
.
更容易完成
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;
}
}
此处 while(is >> ...)
将继续解析文本,只要它遵循该模式。
所以我正在读取一个 .txt 文件,其中包含多组国际象棋走法。我能够从文件中读取数据并将该行插入到字符串中。
单个国际象棋走法示例如下所示:
1. e4 e5
我编写了以下函数来解析单个棋步:
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);
}
我正在解析字符串并将其存储在自定义的 Move Class 中,因此使用 'this' 运算符。此功能完美运行并存储单个国际象棋移动的每个字段。 move[0] 存储第一个着法,move[1] 存储第二个着法,而 moveNumber 数据成员存储着法的编号。
我正在创建一个 Move Class 数组,以便按顺序存储国际象棋比赛的每一步。然而,一套完整的国际象棋走法可能看起来像这样:
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
我很难弄清楚如何从一组国际象棋动作中将这些单独的动作存储在 Move Class 数组中。
主要问题是只读取字符串直到找到移动编号。然后我需要获得一个移动的子字符串(类似于 4. b3 Bg7
然后使用上述函数解析这个单一的国际象棋移动以便我可以存储 moveNumber=4、move[0]="b3" 和 move[1 ]="Bg7" 最后存储到数组类型 Move Class 的相应索引中。然后重复此操作,直到所有移动都一一存储,我们到达字符串的末尾。
编辑:这是我的 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);
}
}
我将所有动作存储在这个数组中:
MoveNode *setofMoves = new MoveNode[totalMoves];
您可以为此使用正则表达式:
- 重复搜索的模式是:
(\d+)\.
一个或多个数字(我们要捕获,因此使用括号),后跟一个点;然后\s+([^\s]+)
一个或多个空格,然后是一个或多个非空格(我们捕获后者);我们重复这种模式两次,每次移动一次;最后(:?\s+|$)
,一个或多个空格\s+
或|
表达式的末尾$
因为输入行可能以第二步结束(我们不捕获这个组(:?)
).
我们使用std::regex
来存储模式,将其全部包装在R"()"
中,以便我们可以编写原始表达式。 while
循环做了一些事情:它搜索与regex_search
的下一个匹配,提取捕获的组(移动编号,移动 0 和移动 1),并更新输入行,这样下一次搜索将从当前搜索结束的地方开始。matches
是一个数组,其第一个元素matches[0]
是line
匹配整个模式的部分,下一个元素对应于模式的捕获组。
#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();
}
}
// Outputs:
// moveNum=1, move[0]=Nf3, move[1]=Nf6
// moveNum=2, move[0]=c4, move[1]=c6
// moveNum=3, move[0]=g3, move[1]=g6
// moveNum=4, move[0]=b3, move[1]=Bg7
// moveNum=5, move[0]=Bb2, move[1]=O-O
// moveNum=6, move[0]=Bg2, move[1]=d5
// moveNum=7, move[0]=O-O, move[1]=Bf5
// moveNum=8, move[0]=d3, move[1]=Nbd7
// moveNum=9, move[0]=Nd4, move[1]=e6
// moveNum=10, move[0]=h3, move[1]=h5
@rturrado 展示了如何使用正则表达式做到这一点,但是我会犹豫这样做,因为 std::regex
很重,需要很多有关正则表达式的知识以有效地使用它。相反,我认为使用 istream
和 operator>>
.
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;
}
}
此处 while(is >> ...)
将继续解析文本,只要它遵循该模式。