在 C++ 中解析具有特定格式的字符串
Posted
技术标签:
【中文标题】在 C++ 中解析具有特定格式的字符串【英文标题】:Parsing a string in c++ with a specfic format 【发布时间】:2021-12-28 18:26:13 【问题描述】:我有这个字符串post "ola tudo bem como esta" alghero.jpg
,我想把它分成三部分post
,ola tudo bem como esta
(我不想要“”)和alghero.jpg
我在c中试过,因为我是新的,不是很好在用 c++ 编程,但它不起作用。在 c++ 中有没有更有效的方法来做到这一点?
程序:
int main()
char* token1 = new char[128];
char* token2 = new char[128];
char* token3 = new char[128];
char str[] = "post \"ola tudo bem como esta\" alghero.jpg";
char *token;
/* get the first token */
token = strtok(str, " ");
//walk through other tokens
while( token != NULL )
printf( " %s\n", token );
token = strtok(NULL, " ");
return(0);
【问题讨论】:
std::stringstream
可能会有所帮助
使用std::string
可以使用find
和substr
。
但究竟如何?
当你说你需要解析一些东西时,重要的是要清楚你期望数据如何被格式化。也就是说,如果您只想解析一个字符串,那么您可以对结果进行硬编码,因此大概您想要解析与post "ola tudo bem como esta" alghero.jpg
格式相同的其他字符串。我们对这些字符串有什么期望?总是由单个空格分隔的三元组 在 C++14 及更高版本中,您可以使用std::quoted
从任何std::istream
中读取带引号的字符串,例如std::istringstream
,例如:
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
int main()
std::string token1, token2, token3;
std::string str = "post \"ola tudo bem como esta\" alghero.jpg";
std::istringstream(str) >> token1 >> std::quoted(token2) >> token3;
std::cout << token1 << "\n";
std::cout << token2 << "\n";
std::cout << token3 << "\n";
return 0;
【讨论】:
【参考方案2】:使用find
查找两个引号的位置。使用substr
获取从索引 0 到第一个引号、第一个引号到第二个引号、第二个引号到结尾的字符串。
std::string s = "post \"ola tudo bem como esta\" alghero.jpg";
auto first = s.find('\"');
if (first != s.npos)
auto second = s.find('\"', first + 1);
if (second != s.npos)
std::cout << s.substr(0, first-1) << '\n';
std::cout << s.substr(first+1, second-first-1) << '\n';
std::cout << s.substr(second+2) << '\n';
输出:
post
ola tudo bem como esta
alghero.jpg
【讨论】:
【参考方案3】:解析字符串的一个选项是使用正则表达式,例如:
#include <iostream>
#include <regex>
#include <string>
// struct to hold return value of parse function
struct parse_result_t
bool parsed false ;
std::string token1;
std::string token2;
std::string token3;
;
// the parse function
auto parse(const std::string& string)
// this is a regex
// ^ match start of line
// (.*)\\\" matches any character until a \" (escaped ") and then escaped again for C++ string
// \w+ match one or more whitepsaces
// (.*)$ match 0 or more characters until end of string
// see it live here : https://regex101.com/r/XnkAZV/1
static std::regex rx "^(.*?)\\s+\\\"(.*?)\\\"\\s+(.*)$" ;
std::smatch match;
parse_result_t result;
if (std::regex_search(string, match, rx))
result.parsed = true;
result.token1 = match[1];
result.token2 = match[2];
result.token3 = match[3];
return result;
int main()
auto result = parse("post \"ola tudo bem como esta\" alghero.jpg");
std::cout << "parse result = " << (result.parsed ? "success" : "failed") << "\n";
std::cout << "token 1 = " << result.token1 << "\n";
std::cout << "token 2 = " << result.token2 << "\n";
std::cout << "token 3 = " << result.token3 << "\n";
return 0;
【讨论】:
【参考方案4】:如果字符串总是由一个空格分隔,您可以使用std::string::find
和 std::string::rfind` 找到第一个空格和最后一个空格,拆分这些字符,然后取消引用中间字符串:
#include <iostream>
#include <tuple>
#include <string>
std::string unquote(const std::string& str)
if (str.front() != '"' || str.back() != '"')
return str;
return str.substr(1, str.size() - 2);
std::tuple < std::string, std::string, std::string> parse_triple_with_quoted_middle(const std::string& str)
auto iter1 = str.begin() + str.find(' ');
auto iter2 = str.begin() + str.rfind(' ');
auto str1 = std::string(str.begin(),iter1);
auto str2 = std::string(iter1 + 1, iter2);
auto str3 = std::string(iter2 + 1, str.end() );
return str1, unquote(str2), str3 ;
int main()
std::string test = "post \"ola tudo bem como esta\" alghero.jpg";
auto [str1, str2, str3] = parse_triple_with_quoted_middle(test);
std::cout << str1 << "\n";
std::cout << str2 << "\n";
std::cout << str3 << "\n";
不过,您可能应该在上面添加更多输入验证。
【讨论】:
【参考方案5】:您可以为此使用正则表达式:
重复搜索的模式是:可选地以空格开头\s*
;然后([^\"]*)
除引号之外的零个或多个字符(零个或多个,因为您可以一个接一个地使用多个引号);我们捕获了这个组(因此使用了括号);最后,无论是引用\"
还是|
表达式的结尾$
;而且我们不会捕获(:?)
这个组。我们使用std::regex
来存储模式,将其全部包装在R"()"
中,这样我们就可以编写原始表达式。
while
循环做了一些事情:它使用regex_search
搜索下一个匹配项,提取捕获的组,并更新输入行,以便下一次搜索将从当前搜索完成的位置开始。matches
是一个数组,其第一个元素 matches[0]
是匹配整个模式的line
的一部分,下一个元素对应于模式的捕获组。
[Demo]
#include <iostream> // cout
#include <regex> // regex_search, smatch
int main()
std::string line"post \"ola tudo bem como esta\" alghero.jpg";
std::regex patternR"(\s*([^\"]*)(:?\"|$))";
std::smatch matches;
while (std::regex_search(line, matches, pattern))
std::cout << matches[1] << "\n";
line = matches.suffix();
【讨论】:
以上是关于在 C++ 中解析具有特定格式的字符串的主要内容,如果未能解决你的问题,请参考以下文章
如何解析具有特定格式数据的文本文件并使用 perl 将其存储在哈希中
将字符串转换为 Excel 日期和时间,具有特定的字符串格式