在C中是否有办法解析一段文本并获取argv和argc的值,就像文本已经在命令行中传递给应用程序一样?
这不一定适用于Windows,只需Linux - 我也不关心引用参数.
R..*_*R.. 29
我很惊讶没有人使用标准POSIX功能提供最简单的答案:
http://www.opengroup.org/onlinepubs/9699919799/functions/wordexp.html
小智 14
这是我的贡献.它很好而且很短,但需要注意的是:
代码:
enum { kMaxArgs = 64 };
int argc = 0;
char *argv[kMaxArgs];
char *p2 = strtok(commandLine, " ");
while (p2 && argc < kMaxArgs-1)
{
argv[argc++] = p2;
p2 = strtok(0, " ");
}
argv[argc] = 0;
Run Code Online (Sandbox Code Playgroud)
您现在可以使用argc和argv,或将它们传递给声明为"foo(int argc,char**argv)"的其他函数.
Rem*_*o.D 12
如果glib解决方案对您的情况来说太过分了,您可以考虑自己编写一个.
然后你可以:
下图应该澄清(希望):
aa bbb ccc "dd d" ee <- original string
aa0bbb0ccc00dd d00ee0 <- transformed string
| | | | |
argv[0] __/ / / / /
argv[1] ____/ / / /
argv[2] _______/ / /
argv[3] ___________/ /
argv[4] ________________/
Run Code Online (Sandbox Code Playgroud)
可能的API可能是:
char **parseargs(char *arguments, int *argc);
void freeparsedargs(char **argv);
Run Code Online (Sandbox Code Playgroud)
您需要其他注意事项才能安全地实现freeparsedargs().
如果您的字符串很长并且您不想扫描两次,则可以考虑使用替代方法,例如为argv数组分配更多元素(如果需要,还可以重新分配).
编辑:提出的解决方案(des not handle引用的参数).
#include <stdio.h>
static int setargs(char *args, char **argv)
{
int count = 0;
while (isspace(*args)) ++args;
while (*args) {
if (argv) argv[count] = args;
while (*args && !isspace(*args)) ++args;
if (argv && *args) *args++ = '\0';
while (isspace(*args)) ++args;
count++;
}
return count;
}
char **parsedargs(char *args, int *argc)
{
char **argv = NULL;
int argn = 0;
if (args && *args
&& (args = strdup(args))
&& (argn = setargs(args,NULL))
&& (argv = malloc((argn+1) * sizeof(char *)))) {
*argv++ = args;
argn = setargs(args,argv);
}
if (args && !argv) free(args);
*argc = argn;
return argv;
}
void freeparsedargs(char **argv)
{
if (argv) {
free(argv[-1]);
free(argv-1);
}
}
int main(int argc, char *argv[])
{
int i;
char **av;
int ac;
char *as = NULL;
if (argc > 1) as = argv[1];
av = parsedargs(as,&ac);
printf("== %d\n",ac);
for (i = 0; i < ac; i++)
printf("[%s]\n",av[i]);
freeparsedargs(av);
exit(0);
}
Run Code Online (Sandbox Code Playgroud)
永远在线的精彩油嘴有g_shell_parse_args()
这听起来像你以后.
如果你对引用甚至不感兴趣,这可能是过度的.您需要做的就是使用空格作为标记字符进行标记.写一个简单的例程来做到这一点不应该花很长时间,真的.
如果你对记忆并不吝啬,那么在没有重新分配的情况下一次性完成它应该很容易; 假设每个第二个字符都是空格的最坏情况,因此假设一串n
字符最多包含(n + 1) / 2
参数,并且(当然)最多n
包含参数文本字节(不包括终结符).
这是Windows和Unix的解决方案(在Linux,OSX和Windows上测试).与Valgrind和记忆博士一起测试.
它使用wordexp用于POSIX系统,而CommandLineToArgvW用于Windows.
请注意,对于Windows的解决方案,大部分代码之间转换char **
,并wchar_t **
与美丽的Win32 API的,因为没有CommandLineToArgvA
可用的(ANSI版本).
#ifdef _WIN32
#include <windows.h>
#else
#include <wordexp.h>
#endif
char **split_commandline(const char *cmdline, int *argc)
{
int i;
char **argv = NULL;
assert(argc);
if (!cmdline)
{
return NULL;
}
// Posix.
#ifndef _WIN32
{
wordexp_t p;
// Note! This expands shell variables.
if (wordexp(cmdline, &p, 0))
{
return NULL;
}
*argc = p.we_wordc;
if (!(argv = calloc(*argc, sizeof(char *))))
{
goto fail;
}
for (i = 0; i < p.we_wordc; i++)
{
if (!(argv[i] = strdup(p.we_wordv[i])))
{
goto fail;
}
}
wordfree(&p);
return argv;
fail:
wordfree(&p);
}
#else // WIN32
{
wchar_t **wargs = NULL;
size_t needed = 0;
wchar_t *cmdlinew = NULL;
size_t len = strlen(cmdline) + 1;
if (!(cmdlinew = calloc(len, sizeof(wchar_t))))
goto fail;
if (!MultiByteToWideChar(CP_ACP, 0, cmdline, -1, cmdlinew, len))
goto fail;
if (!(wargs = CommandLineToArgvW(cmdlinew, argc)))
goto fail;
if (!(argv = calloc(*argc, sizeof(char *))))
goto fail;
// Convert from wchar_t * to ANSI char *
for (i = 0; i < *argc; i++)
{
// Get the size needed for the target buffer.
// CP_ACP = Ansi Codepage.
needed = WideCharToMultiByte(CP_ACP, 0, wargs[i], -1,
NULL, 0, NULL, NULL);
if (!(argv[i] = malloc(needed)))
goto fail;
// Do the conversion.
needed = WideCharToMultiByte(CP_ACP, 0, wargs[i], -1,
argv[i], needed, NULL, NULL);
}
if (wargs) LocalFree(wargs);
if (cmdlinew) free(cmdlinew);
return argv;
fail:
if (wargs) LocalFree(wargs);
if (cmdlinew) free(cmdlinew);
}
#endif // WIN32
if (argv)
{
for (i = 0; i < *argc; i++)
{
if (argv[i])
{
free(argv[i]);
}
}
free(argv);
}
return NULL;
}
Run Code Online (Sandbox Code Playgroud)