[英]String split in C with strtok function
我正在尝试用{white_space}符号分割一些字符串。 顺便说一句,在某些分裂中存在问题。 这意味着,我想用{white_space}符号分割,但还要引用子字符串。
例,
char *pch;
char str[] = "hello \"Stack Overflow\" good luck!";
pch = strtok(str," ");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok(NULL, " ");
}
这会给我
hello
"Stack
Overflow"
good
luck!
但是我想要的,如你所知,
hello
Stack Overflow
good
luck!
有什么建议或想法吗?
您需要两次标记化。 您当前拥有的程序流程如下:
1)搜索空间
2)在空格之前打印所有字符
3)搜索下一个空间
4)打印最后一个空格和该空格之间的所有字符。
您需要开始思考另一件事,即两层标记化。
在这种情况下,偶数编号的字符串(理想情况下)应放在引号内。 ab“ cd” ef将导致ab为奇数,cd为偶数...等等。
另一面,是记住您需要做的事情,而您实际正在寻找的(在正则表达式中)是“ [a-zA-Z0-9 \\ t \\ n] *”或[a-zA-Z0- 9] +。 这意味着两个选项之间的区别在于是否用引号将其分开。 因此,请用引号将其分开,并从中识别。
尝试改变策略。
查看非空格的东西,然后在找到带引号的字符串时,可以将其放在一个字符串值中。
因此,您需要一个在空白之间检查字符的函数。 当您找到'"'
您可以更改规则并将所有内容悬停在匹配的'"'
。 如果此函数返回一个TOKEN值和一个值(匹配的字符串),则调用它的对象可以决定进行正确的输出。 然后,您编写了标记程序,并且实际上存在一些工具来生成它们(称为“词法分析器”),因为它们被广泛使用以实现编程语言/配置文件。
假设nextc从字符串中读取下一个char,由firstc(str)开始:
for (firstc( str); ((c = nextc) != NULL;) {
if (isspace(c))
continue;
else if (c == '"')
return readQuote; /* Handle Quoted string */
else
return readWord; /* Terminated by space & '"' */
}
return EOS;
您需要定义EOS,QUOTE和WORD的返回值,以及一种在每个Quote或Word中获取文本的方法。
这是在C中工作的代码
想法是您首先标记引号,因为这是优先级(如果引号内有字符串,而不是不标记的话,我们只打印它)。 对于每个标记化的字符串,我们在空格字符上的该字符串内进行标记化,但是我们对替代字符串进行标记化,因为替代字符串将在引号内和引号外。
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
int main() {
char *pch1, *pch2, *save_ptr1, *save_ptr2;
char str[] = "hello \"Stack Overflow\" good luck!";
pch1 = strtok_r(str,"\"", &save_ptr1);
bool in = false;
while (pch1 != NULL) {
if(in) {
printf ("%s\n", pch1);
pch1 = strtok_r(NULL, "\"", &save_ptr1);
in = false;
continue;
}
pch2 = strtok_r(pch1, " ", &save_ptr2);
while (pch2 != NULL) {
printf ("%s\n",pch2);
pch2 = strtok_r(NULL, " ", &save_ptr2);
}
pch1 = strtok_r(NULL, "\"", &save_ptr1);
in = true;
}
}
参考
它在C ++中。 我相信它可以写得更优美,但是它是可行的并且是一个开始:
#include <iostream>
#include <stdexcept>
#include <vector>
#include <string>
using namespace std;
using Tokens = vector<string>;
Tokens split(string const & sentence) {
Tokens tokens;
// indexes to split on
string::size_type from = 0, to;
// true if we are inside quotes: we don't split by spaces and we expect a closing quote
// false otherwise
bool in_quotes = false;
while (true) {
// compute to index
if (!in_quotes) {
// find next space or quote
to = sentence.find_first_of(" \"", from);
if (to != string::npos && sentence[to] == '\"') {
// we found an opening quote
in_quotes = true;
}
} else {
// find next quote (ignoring spaces)
to = sentence.find('\"', from);
if (to == string::npos) {
// no enclosing quote found, invalid string
throw invalid_argument("missing enclosing quotes");
}
in_quotes = false;
}
// skip empty tokens
if (from != to) {
// get token
// last token
if (to == string::npos) {
tokens.push_back(sentence.substr(from));
break;
}
tokens.push_back(sentence.substr(from, to - from));
}
// move from index
from = to + 1;
}
return tokens;
}
测试一下:
void splitAndPrint(string const & sentence) {
Tokens tokens;
cout << "-------------" << endl;
cout << sentence << endl;
try {
tokens = split(sentence);
} catch (exception &e) {
cout << e.what() << endl;
return;
}
for (const auto &token : tokens) {
cout << token << endl;
}
cout << endl;
}
int main() {
splitAndPrint("hello \"Stack Overflow\" good luck!");
splitAndPrint("hello \"Stack Overflow\" good luck from \"User Name\"");
splitAndPrint("hello and good luck!");
splitAndPrint("hello and \" good luck!");
return 0;
}
输出:
-------------
hello "Stack Overflow" good luck!
hello
Stack Overflow
good
luck!
-------------
hello "Stack Overflow" good luck from "User Name"
hello
Stack Overflow
good
luck
from
User Name
-------------
hello and good luck!
hello
and
good
luck!
-------------
hello and " good luck!
missing enclosing quotes
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.