代码之家  ›  专栏  ›  技术社区  ›  KateMak

通过delimeter拆分一个char数组,然后保存结果?

  •  1
  • KateMak  · 技术社区  · 13 年前

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

    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上玩了大约两个小时了,现在我遇到了麻烦。有人有什么想法吗?

    3 回复  |  直到 13 年前
        1
  •  1
  •   Alexander Shukaev    13 年前

    我建议你更多地了解 regular expressions 。为了无痛地解决您的问题,您可以使用 Boost.Regex 库,它提供了一个强大的正则表达式引擎。解决方案只有几行代码,但我鼓励您自己动手——这将是一个很好的练习。如果你仍然有问题,回来时给出一些结果,并清楚地说明你被卡住的地方。

        2
  •  1
  •   Jamin Grey    13 年前

    您可以使用std::getline(stream、stringToReadInto、delimeter)。

    我个人使用我自己的功能,其中包含一些附加功能,看起来如下:

    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”是的typedef std::矢量 ,而CharValidatorFunc是一个函数指针(实际上,std::函数允许functor和lambda支持),用于获取一个char并返回一个bool的函数。它可以这样使用:

    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()中,然后将其传递给函数,除非需要极高的性能。打破delimeters是相当容易推出您自己的-上面的功能只是根据我的项目的典型用途和要求定制的,但您可以随意修改它并自行声明。

        3
  •  0
  •   KateMak    13 年前

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

    //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
    
    推荐文章