c - 如何用分号解析命令行?
问题描述
我正在尝试读取由分号分隔且前后有空格的命令行参数(例如 ls ; date ; cal ),但分隔部分很困难。当我简单地输入一个单独的命令行(例如ls
or date
)时,我的代码可以工作,但是每当我输入分号时,它就不起作用(例如ls ; date
)
这是我的 C 代码:
void parse(char *userInput, char **splitInput)
{
//read until userInput is not end of line
while (*userInput != '\0')
{
//replace any space in userInput as '\0'
while (*userInput == ';')
{
*userInput++ = '\0';
}
//save the argument position
*splitInput++ = userInput;
//if userinput is not equal to space, read next userInput
while (*userInput != ' ' && *userInput != ';' && *userInput != '\0')
{
userInput++;
}
}
}
void execute(char **splitInput)
{
pid_t pid = fork();
if (pid > 0) //parent process
{
pid_t parent_pid;
parent_pid = wait(NULL);
}
else if (pid == 0) //child process
{
if (execvp(*splitInput, splitInput) < 0)
{
printf("%s: command not found\n", *splitInput);
exit(1);
}
}
else //error
{
perror("fort error");
}
}
void main(void)
{
char userInput[100]; //execvp's first argument
char *splitInput[100]; //execvp's second argument
while(strcmp(userInput,"quit") != 0)
{
//ask for a user input
printf("group 10> ");
//read the entire line of input
scanf("%[^\n]", userInput);
//get characters from input; stop the loop problem
getchar();
//quit if user input is equal to quit
if (strcmp(userInput, "quit") == 0)
{
exit(0);
}
//parse the input
parse(userInput, splitInput);
//execute fork
execute(splitInput);
}
}
解决方案
有很多方法可以做到这一点。string.h
提供了几个可以使用的功能,strtok()
, strsep()
, strchr()
, 或结合使用strcspn()
,strspn()
具体取决于您的需要。您还可以始终沿着字符串向下移动指针,从字符串中挑选出想要的标记,并忽略空格和多重包含分隔符。从教育的角度来看,以这种方式接近它实际上有很好的指针学习价值。
任何时候你循环任何东西,挑选出不同的部分,而不是尝试包含多个嵌套while
循环,每个嵌套循环都设计为向前扫描以跳过或查找特定类别的字符,使用状态循环通常更有利,其中您使用多个标志之一来跟踪不同的状态。(行字内阅读字符,或字之间阅读分隔符或空格等。)。这样就不需要嵌套循环,您只需使用单个循环来循环每个字符,根据您当前的状态做出相应的响应。
将其用于扫描您的字符串并挑选出以分隔符';'
或空格结尾的每个单词,并保留一个状态标志int in;
来跟踪您是在字内阅读字符(in = 1;
)还是在处理空格和分隔符的单词之间(in = 0;
) 并char *sp
用作指向每个单词开头的起始指针和指向正在读取的当前字符userInput
的结束指针,您可以这样做:
void parse(char *userInput, char **splitInput, char delim, size_t nptrs)
{
int in = 0; /* simple in-word flag 0-false/1-true */
size_t n = 0; /* counter to protect splitInput bounds */
char *sp = userInput; /* start-pointer initialized to userInput */
while (n < nptrs - 1) { /* loop while pointers remain unfilled */
/* if at end, is whitespace or a delimiter */
if (!*userInput || isspace(*userInput) || *userInput == delim) {
if (in) { /* if in word */
splitInput[n++] = sp; /* set pointer to start-pointer */
splitInput[n] = NULL; /* set next pointer NULL */
}
in = 0; /* reset in flag zero */
if (*userInput) /* if space or delim, nul-terminate */
*userInput = 0;
else /* otherwise */
return; /* at end-of-string */
}
else { /* normal char */
if (!in) { /* if not in-word */
sp = userInput; /* set start-pointer to 1st good char */
in = 1; /* set in-word flag true */
}
}
userInput++; /* advance to next char */
}
}
(注意:上面的delim
字符作为参数传递,并nptrs
传递您可用的指针数量,因此您可以在填充指针时保护指针数组边界。另请注意,该函数始终将数组中的下一个指针设置NULL
为sentinel 允许您循环遍历数组中的指针,main()
直到NULL
到达,因为您不返回使用的指针数量,无论是作为函数返回还是通过指针参数)
" my; ; ; dog ;;; has;fleas ;"
一个简单的例子,它解析使用或空格作为分隔符的单词';'
可能是:
#include <stdio.h>
#include <ctype.h>
#define NPTR 32 /* if you need a constant, #define one (or more) */
void parse(char *userInput, char **splitInput, char delim, size_t nptrs)
{
int in = 0; /* simple in-word flag 0-false/1-true */
size_t n = 0; /* counter to protect splitInput bounds */
char *sp = userInput; /* start-pointer initialized to userInput */
while (n < nptrs - 1) { /* loop while pointers remain unfilled */
/* if at end, is whitespace or a delimiter */
if (!*userInput || isspace(*userInput) || *userInput == delim) {
if (in) { /* if in word */
splitInput[n++] = sp; /* set pointer to start-pointer */
splitInput[n] = NULL; /* set next pointer NULL */
}
in = 0; /* reset in flag zero */
if (*userInput) /* if space or delim, nul-terminate */
*userInput = 0;
else /* otherwise */
return; /* at end-of-string */
}
else { /* normal char */
if (!in) { /* if not in-word */
sp = userInput; /* set start-pointer to 1st good char */
in = 1; /* set in-word flag true */
}
}
userInput++; /* advance to next char */
}
}
int main (void) {
char s[] = " my; ; ; dog ;;; has;fleas ;", *split[NPTR] = { NULL }, **p = split;
parse (s, split, ';', NPTR);
while (*p)
printf ("'%s'\n", *p++);
}
(注意:包含标头ctype.h
是为了使用该isspace()
函数来测试空格,而不是将if()
检查的语句串在一起space
,'\t'
或者'\n'
直接。这通常是一种很好的做法。)
示例使用/输出
$ ./bin/split_ptr_arr3
'my'
'dog'
'has'
'fleas'
注意在上面的输出中,所有包含的空格都被删除了。
看看事情,如果你有问题,请告诉我。实际上有几十种方法来处理拆分字符串,这只是一种常见和基本的方法。
推荐阅读
- javascript - 在 Web Audio 中,为什么 contextTime 比 baseLatency 滞后 currentTime?
- oop - 实际类型随叫随到
- python - `setCalculateVarImportance` 更改导致 `cv2.ml.RTrees` 模型
- javascript - 我想在其子项处于活动状态时使父导航链接侧边栏处于活动状态(当前页面)
- sql - 使用联合联接查询需要 Oracle 联合澄清
- ng-zorro-antd - 有没有办法在反应形式中使用 nz-checkbox 或 nz-checkbox-group 或 nz-checkbox-wrapper
- php - 获取有关在 PHP LDAP 服务器上执行的任何更新的通知
- angular - 使用 Flex-Layout 的选定扩展面板的最大高度
- c - 这是对 realloc() 的正确使用吗?
- xcode - 有没有办法让 AppleScript 中的按钮和窗口透明?