【问题标题】:Splitting a char array by delimeter, then saving the result?保存结果时按分隔符拆分字符数组?
【发布时间】:2013-03-20 01:41:36
【问题描述】:

我需要能够在我的程序中解析以下两个字符串:

cat myfile || sort
more myfile || grep DeKalb

字符串被保存在字符缓冲区[1024] 中。我最终需要的是一个指向左侧的 char 数组的指针,以及一个指向右侧的 char 数组的指针,以便我可以使用它们为每一侧调用以下内容:

int execvp(const char *file, char *const argv[]); 

如果上面的两个字符串保存在字符缓冲区 char buffer[1024]; 中,任何人都知道如何为 execvp 命令获取正确的参数。 ?

我需要 char *left 来保存左侧的第一个单词,然后 char *const leftArgv[] 来保存左侧的两个单词。然后我需要同样的东西来做正确的事情。我已经在 strtok 上玩了两个小时了,我正在碰壁。有人有什么想法吗?

【问题讨论】:

    标签: c++ c delimiter strtok execvp


    【解决方案1】:

    我建议您了解有关regular expressions 的更多信息。为了轻松解决您的问题,您可以使用Boost.Regex 库,它提供了强大的正则表达式引擎。解决方案只是几行代码,但我鼓励你自己做——这将是一个很好的练习。如果您仍然有问题,请返回一些结果并明确说明您遇到的问题。

    【讨论】:

      【解决方案2】:

      您可以使用 std::getline(stream, stringToReadInto, demeter)。

      我个人使用我自己的函数,其中包含一些附加功能,如下所示:

      StringList Seperate(const std::string &str, char divider, SeperationFlags seperationFlags, CharValidatorFunc whitespaceFunc)
      {
          return Seperate(str, CV_IS(divider), seperationFlags, whitespaceFunc);
      }
      
      StringList Seperate(const std::string &str, CharValidatorFunc isDividerFunc, SeperationFlags seperationFlags, CharValidatorFunc whitespaceFunc)
      {
          bool keepEmptySegments     = (seperationFlags & String::KeepEmptySegments);
          bool keepWhitespacePadding = (seperationFlags & String::KeepWhitespacePadding);
      
          StringList stringList;
      
          size_t startOfSegment = 0;
          for(size_t pos = 0; pos < str.size(); pos++)
          {
              if(isDividerFunc(str[pos]))
              {
                  //Grab the past segment.
                  std::string segment = str.substr(startOfSegment, (pos - startOfSegment));
                  if(!keepWhitespacePadding)
                  {
                      segment = String::RemovePadding(segment);
                  }
      
                  if(keepEmptySegments || !segment.empty())
                  {
                      stringList.push_back(segment);
                  }
      
                  //If we aren't keeping empty segments, speedily check for multiple seperators in a row.
                  if(!keepEmptySegments)
                  {
                      //Keep looping until we don't find a divider.
                      do
                      {
                          //Increment and mark this as the (potential) beginning of a new segment.
                          startOfSegment = ++pos;
      
                          //Check if we've reached the end of the string.
                          if(pos >= str.size())
                          {
                              break;
                          }
                      }
                      while(isDividerFunc(str[pos]));
                  }
                  else
                  {
                      //Mark the beginning of a new segment.
                      startOfSegment = (pos + 1);
                  }
              }
          }
      
          //The final segment.
          std::string lastSegment = str.substr(startOfSegment, (str.size() - startOfSegment));
          if(keepEmptySegments || !lastSegment.empty())
          {
              stringList.push_back(lastSegment);
          }
      
          return stringList;
      }
      

      其中 'StringList' 是 std::vector 的 typedef,而 CharValidatorFunc 是函数指针(实际上,std::function 允许 functor 和 lambda 支持)对于一个接受一个字符并返回一个布尔值的函数。可以这样使用:

      StringList results = String::Seperate(" Meow meow , Green, \t\t\nblue\n   \n, Kitties!", ',' /* delimeter */, DefaultFlags, is_whitespace);
      

      并且会返回结果: {“喵喵”、“绿色”、“蓝色”、“小猫!”}

      保留“喵喵”的内部空格,但删除变量周围的空格、制表符和换行符,并以逗号分隔。

      (CV_IS 是一个仿函数对象,用于匹配特定字符或作为字符串文字的特定字符集合。我还有 CV_AND 和 CV_OR 用于组合字符验证器函数)

      对于字符串文字,我只需将其放入 std::string() 中,然后将其传递给函数,除非需要极高的性能。打破分隔符很容易让你自己滚动 - 上面的函数只是根据我的项目的典型用法和要求定制的,但你可以随意修改它并为自己声明。

      【讨论】:

        【解决方案3】:

        如果这让其他人感到悲伤,这就是我解决问题的方法:

        //variables for the input and arguments
        char *command[2];
        char *ptr;
        char *LeftArg[3];
        char *RightArg[3];
        
        char buf[1024]; //input buffer
        
        //parse left and right of the ||
        number = 0;
        command[0] = strtok(buf, "||");
        
        //split left and right
        while((ptr=strtok(NULL, "||")) != NULL)
        {
            number++;
            command[number]=ptr;
        }
        
        //parse the spaces out of the left side
        number = 0;
        LeftArg[0] = strtok(command[0], " ");
        
        //split the arguments
        while((ptr=strtok(NULL, " ")) != NULL)
        {
            number++;
            LeftArg[number]=ptr;
        }
        
        //put null at the end of the array
        number++;
        LeftArg[number] = NULL;
        
        //parse the spaces out of the right side
        number = 0;
        RightArg[0] = strtok(command[1], " ");
        
        //split the arguments
        while((ptr=strtok(NULL, " ")) != NULL)
        {
                number++;
                RightArg[number]=ptr;
        }
        
        //put null at the end of the array
        number++;
        RightArg[number] = NULL;
        

        现在你可以在命令中使用 LeftArg 和 RightArg,在你得到正确的管道之后

        execvp(LeftArg[0], LeftArg);//execute left side of the command
        

        然后管道到命令的右侧并执行

        execvp(RightArg[0], RightArg);//execute right side of command
        

        【讨论】:

        • 请注意,这不是我的程序的完整工作代码。这只是为了向您展示如何完成我的问题中的部分。
        • 部分原因是,是的。另一部分是好奇心。
        猜你喜欢
        • 1970-01-01
        • 2012-01-16
        • 1970-01-01
        • 1970-01-01
        • 2015-02-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-08
        相关资源
        最近更新 更多