【问题标题】:Searching for an alternative for strtok() in C++在 C++ 中寻找 strtok() 的替代方法
【发布时间】:2025-12-12 10:20:05
【问题描述】:

我正在使用 strtok 将字符串分成几个部分。 在此示例中,将从字符串中读取所有部分,以冒号或分号为界

char string[] = "Alice1:IscoolAlice2; Alert555678;Bob1:knowsBeepBob2;sees";
char delimiter[] = ":;";
char *p;

p = strtok(string, delimiter);

while(p != NULL) {
    cout << "Result: " << p << endl;

    p = strtok(NULL, delimiter);
}

我得到的结果:

Result: Alice1
Result: IscoolAlice2
Result:  Alert555678
Result: Bob1
Result: knowsBeepBob2
Result: sees

但我想得到这个结果:

Result: Alice1:
Result: Alice2;
Result: Bob1:
Result: Bob2;

限制是我在使用 strtok 时只能选择单个字符。 有谁知道我也可以搜索字符串的 strtok 替代方案? 或者有没有人想办法解决我的问题?

【问题讨论】:

  • 你打算如何将 Iscool 这个词从 Alice2 中分离出来?没有差距。
  • 你可能想要boost::tokenizer
  • 我认为您需要提供更清晰的问题陈述。您似乎正在寻找在 : 之后或之前出现的东西:由 ; 分隔。然后取最后一个大写字母之后的所有内容。

标签: c++ split strtok


【解决方案1】:

您无法使用 strtok 完成该任务,因为您需要更复杂的搜索

虽然我不确定你的 string 是什么分隔符,但同样的输出可以用:

char string[] = "Alice1:IscoolAlice2; Alert555678;Bob1:knowsBeepBob2;sees";
char delimiter[] = "(?:Alice|Bob)\\d.";
std::regex regex( delimiter );
std::regex_iterator< const char* > first( std::begin( string ), std::end( string ), regex  ), last;

while( first != last ){
    std::cout << "Result: " << first->str() << '\n';
    ++first;
}  

输出:

Result: Alice1;
Result: Alice2;
Result: Bob1;
Result: Bob2;

【讨论】:

  • 非常感谢k-5!这正是我所需要的!
  • @Kadamu 不是问题
【解决方案2】:

这只是一个简单的从头开始的逻辑,大致如下:

char *ptr = string;

while(*ptr)
{
   printf("Result:");
   while(*ptr)
   {
      printf("%c", *ptr);
      if(ispunc(*ptr))
      {
         ptr++;
         printf("\n");
         break;
      }
      else
      {
         ptr++;
      }
   }
}

【讨论】:

    【解决方案3】:

    您声明的数据集无法按照您想要的方式正确拆分。您可以想出一个“就这样”的规则,从字面上拆分您显示的数据,但鉴于数据的混乱性质,它很可能会在其他示例中失败。让我们从这个令牌开始。

    IscoolAlice2
    

    计算机程序应该如何知道其中的哪一部分是名称,哪一部分不是?你想从中得到“Alice2”。如果您决定一个大写字母指定一个名称,那么它只会吐出“名称”IscoolAlice2。与以下相同:

    knowsBeepBob2
    

    如果您搜索第一个大写字母,那么程序将确定他的名字是 BeepBob2,因此在每种情况下搜索令牌中最后出现的大写字母都会找到该名称。但是如果一个名字包含两个大写字母呢?该程序将删除他们的名字,而您对此无能为力。

    如果您乐于忍受这些限制,您可以通过 strtok 进行初始拆分,仅使用 ;字符,它给出:

    Alice1:IscoolAlice2
     Alert555678
    Bob1:knowsBeepBob2
    sees
    

    这不太理想。然后,您可以指定一个规则,使得名称存在于包含 : 的任何行中,将 : 的任何左侧作为名称,然后找到最后一个大写字母,并且从该点开始的任何内容也是名称。这会给你你想要的输出。

    但我概述的规则对刚刚输入的数据非常具体。如果其他数据样本的任何内容与此完全不同(例如,其中包含两个大写字母的名称),那么它将失败,因为会有在地球上,程序无法确定“名称”的开始位置。

    解决此问题的唯一方法是返回数据的来源并以不同的格式对其进行格式化,以便名称前有某种标点符号。

    或者,您需要一个包含所有可能出现的名称的完整数据库,然后搜索它们,找到直到下一个 : 或 ; 的任何字符并附加它们并打印名称。但这似乎非常不切实际。

    【讨论】: