【问题标题】:String split in C with strtok function使用 strtok 函数在 C 中拆分字符串
【发布时间】:2014-07-27 20:25:52
【问题描述】:

我正在尝试用 {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!

有什么建议或想法吗?

【问题讨论】:

  • 你正在分割空间,你得到的正是你想要的。引号只是字符串中的另一个字符。
  • 您必须自己进行解析:检查您是否介于开头" 和结尾" 之间。
  • 如果我为你写一个 C++ 实现可以吗?我懒得用 C 写这个了。
  • @Happington 哦!我已经在里面完成了编辑问题!有一些误解来解释我的问题:
  • 无论如何,看看 C++ 会很有趣。 strtok,有点坏,例如不处理空字段。

标签: c string split arguments


【解决方案1】:

尝试改变你的策略。

查看非空白的东西,然后当你找到带引号的字符串时,你可以把它放在一个字符串值中。

因此,您需要一个检查空格之间的字符的函数。当您找到'"' 时,您可以更改规则并将所有内容搜索到匹配的'"'。如果这个函数返回一个 TOKEN 值和一个值(匹配的字符串)然后调用它,可以决定做正确的输出。然后,您编写了一个分词器,实际上存在生成它们的工具,称为“词法分析器”,因为它们被广泛使用,以实现编程语言/配置文件。

假设 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 的返回值,以及获取每个 Quote 或 Word 中文本的方法。

【讨论】:

    【解决方案2】:

    您需要标记两次。你目前的程序流程如下:

    1) 搜索空间

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

    3) 搜索下一个空格

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

    您需要开始考虑不同的问题,两层标记化。

    1. 搜索引号
    2. 在奇数字符串上,执行您的原始程序(搜索空格)
    3. 在偶数字符串上,盲目打印

    在这种情况下,偶数字符串(理想情况下)在引号内。 ab"cd"ef 将导致 ab 为奇数,cd 为偶数......等等。

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

    【讨论】:

      【解决方案3】:

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

      参考文献

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-03-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多