在C ++中模仿shell参数解析器

时间:2011-04-04 04:39:43

标签: c++ regex command-line command-line-arguments

我一直在研究一个模仿shell终端的程序,而且我遇到的实现问题比我预想的要困难。基本上,我试图拆分参数,就像shell传递给它的可执行文件一样。所以,想象一下如下的输入:

$> ./foo some arguments

可以预期传递给程序的参数就像一个数组(假设是C / C ++):

char ** argv = {"foo", "some" "arguments"}

但是,如果论点是:

$> ./foo "My name is foo" bar

数组将是:

char ** argv = {"foo", "My name is foo", "bar"}

任何人都可以建议一种有效的方法来实现它,这样界面就像:

vector<string> splitArgs(string allArgs);string[] splitArgs(string allArgs);

当然,我可以简单地迭代并在“阅读单词”/“阅读引用文本”的状态之间切换,但我觉得这并不像它可能那样有效。我也玩弄了正则表达式的想法,但我不熟悉如何在C ++中完成。对于这个项目,如果有帮助,我也会安装boost库。

谢谢! RR

2 个答案:

答案 0 :(得分:0)

我有时仍然使用这个普通的C效用函数。我主要在嵌入式系统上使用它,其中有一个非常有限的标准库,因此大多数代码可以使用标准的lib控件更改为更高效,但基本技术应该保持不变,标记字符串的引用部分在解析之前,然后通过拆分标记来分解单独标记中的字符串,最后消除各个部分的引号。

/**
 * Split a line into separate words.
 */
static void splitLine(char *pLine, char **pArgs) {
    char *pTmp = strchr(pLine, ' ');

    if (pTmp) {
        *pTmp = '\0';
        pTmp++;
        while ((*pTmp) && (*pTmp == ' ')) {
            pTmp++;
        }
        if (*pTmp == '\0') {
            pTmp = NULL;
        }
    }
    *pArgs = pTmp;
}



/**
 * Breaks up a line into multiple arguments.
 *
 * @param io_pLine Line to be broken up.
 * @param o_pArgc Number of components found.
 * @param io_pargc Array of individual components
 */
static void parseArguments(char *io_pLine, int *o_pArgc, char **o_pArgv) {
    char *pNext = io_pLine;
    size_t i;
    int j;
    int quoted = 0;
    size_t len = strlen(io_pLine);

    // Protect spaces inside quotes, but lose the quotes
    for(i = 0; i < len; i++) {
        if ((!quoted) && ('"' == io_pLine[i])) {
            quoted = 1;
            io_pLine[i] = ' ';
        } else if ((quoted) && ('"' == io_pLine[i])) {
            quoted = 0;
            io_pLine[i] = ' ';
        } else if ((quoted) && (' ' == io_pLine[i])) {
            io_pLine[i] = '\1';
        }
    }

    // init
    MY_memset(o_pArgv, 0x00, sizeof(char*) * C_MAXARGS);
    *o_pArgc = 1;
    o_pArgv[0] = io_pLine;

    while ((NULL != pNext) && (*o_pArgc < C_MAXARGS)) {
        splitLine(pNext, &(o_pArgv[*o_pArgc]));
        pNext = o_pArgv[*o_pArgc];

        if (NULL != o_pArgv[*o_pArgc]) {
            *o_pArgc += 1;
        }
    }

    for(j = 0; j < *o_pArgc; j++) {
        len = strlen(o_pArgv[j]);
        for(i = 0; i < len; i++) {
            if('\1' == o_pArgv[j][i]) {
                o_pArgv[j][i] = ' ';
            }
        }
    }
}

答案 1 :(得分:-1)

将整个字符串传递给shell可能符合您的需求:

例如:

System("./foo some arguments");

不是最好的解决方案

更好的方法似乎是写parser to find each argument并将其传递给exec style function