字符串在C中用strtok函数拆分

时间:2014-06-06 14:16:50

标签: c string split arguments

我试图通过{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!

有任何建议或想法吗?

4 个答案:

答案 0 :(得分:2)

你需要两次令牌化。您目前拥有的程序流程如下:

1)搜索空间

2)打印空格前的所有字符

3)搜索下一个空格

4)打印最后一个空格和此空格之间的所有字符。

你需要开始思考另一个问题,即两层标记化。

  1. 搜索引号
  2. 在奇数编号的字符串上,执行原始程序(搜索空格)
  3. 在偶数编号的字符串上,盲目打印
  4. 在这种情况下,偶数编号的字符串(理想情况下)在引号内。 ab“cd”ef会导致ab为奇数,cd为偶数......等等。

    另一方面,正在记住你需要做什么,你正在寻找的(在正则表达式中)是“[a-zA-Z0-9 \ t \ n] *”或者,[a-zA -Z0-9] +。这意味着两个选项之间的区别在于它是否用引号分隔。所以用引号分开,并从那里识别。

答案 1 :(得分:1)

尝试改变策略。

查看非白色空格,然后当找到带引号的字符串时,可以将其放在一个字符串值中。

因此,您需要一个在空白区域之间检查字符的函数。当您找到'"'时,您可以更改规则并将所有内容转移到匹配的'"'。如果此函数返回TOKEN值和值(匹配的字符串),那么调用它可以决定执行正确的输出。然后你编写了一个tokeniser,实际上存在生成它们的工具,叫做" lexers"因为它们被广泛使用,用于实现编程语言/配置文件。

假设nextc从字符串中读取下一个字符,由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定义返回值,以及在每个引用或Word中获取文本的方法。

答案 2 :(得分:0)

这是在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;
  }
}

参考

答案 3 :(得分:-1)

这是在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