如何用分号解析命令行?
How can I parse the command line with semicolons?
我正在尝试阅读由分号分隔的命令行参数,前后有一个空白 space(例如 ls ; date ; cal),但分隔部分一直很困难。当我简单地放置一个单独的命令行(例如 ls
或 date
)时,我的代码可以工作,但是每当我放置分号时,它就不起作用(例如 ls ; date
)
这是我的 C 代码:
void parse(char *userInput, char **splitInput)
{
//read until userInput is not end of line
while (*userInput != '[=10=]')
{
//replace any space in userInput as '[=10=]'
while (*userInput == ';')
{
*userInput++ = '[=10=]';
}
//save the argument position
*splitInput++ = userInput;
//if userinput is not equal to space, read next userInput
while (*userInput != ' ' && *userInput != ';' && *userInput != '[=10=]')
{
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()
的组合,看你的需要.您也可以始终 walk-a-pointer 沿着字符串从字符串中挑选出想要的标记并忽略空格和 multiple-included-delimiters。从教育的角度来看,以这种方式接近它实际上有很好的指针学习价值。
任何时候你在循环任何东西时挑选出不同的部分,而不是试图包含多个嵌套的 while
循环,每个循环都设计为 scan-forward 跳过或找到特定的 class 的字符,使用 state-loop 通常更有利,您可以在其中使用多个 flags 来跟踪不同的状态. (第 in-word 行读取字符,或在单词之间读取定界符或空格等。)。这样就不需要嵌套循环,您只需使用一个循环来遍历每个字符,根据您当前的状态做出相应的响应。
将其用于扫描您的字符串并挑选出每个以定界符 ';'
或空格终止的单词,并保留一个状态标志 int in;
以跟踪您是否in-word 读取字符 (in = 1;
) 或在单词之间处理空格和分隔符 (in = 0;
) 并使用 char *sp
作为 start-pointer 指向每个单词的开头, userInput
作为 end-pointer 指向当前正在读取的字符,你可以这样做:
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
作为标记,允许您循环遍历 main()
中数组中的指针,直到 [=达到 28=] 是因为您没有 return 使用的指针数量,无论是作为函数 return 还是通过指针参数)
一个使用 ';'
或空格作为分隔符解析来自 " 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++);
}
(注意: 包含 header ctype.h
是为了利用 isspace()
函数来测试空格而不是串在一起if()
语句直接检查 space
、'\t'
或 '\n'
。这通常是很好的做法。)
例子Use/Output
$ ./bin/split_ptr_arr3
'my'
'dog'
'has'
'fleas'
注意上面的输出中所有包含的空格都被删除了。
检查一下,如果您有任何问题,请告诉我。拆分字符串的方法有很多种,这只是一种常见的基本方法。
我正在尝试阅读由分号分隔的命令行参数,前后有一个空白 space(例如 ls ; date ; cal),但分隔部分一直很困难。当我简单地放置一个单独的命令行(例如 ls
或 date
)时,我的代码可以工作,但是每当我放置分号时,它就不起作用(例如 ls ; date
)
这是我的 C 代码:
void parse(char *userInput, char **splitInput)
{
//read until userInput is not end of line
while (*userInput != '[=10=]')
{
//replace any space in userInput as '[=10=]'
while (*userInput == ';')
{
*userInput++ = '[=10=]';
}
//save the argument position
*splitInput++ = userInput;
//if userinput is not equal to space, read next userInput
while (*userInput != ' ' && *userInput != ';' && *userInput != '[=10=]')
{
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()
的组合,看你的需要.您也可以始终 walk-a-pointer 沿着字符串从字符串中挑选出想要的标记并忽略空格和 multiple-included-delimiters。从教育的角度来看,以这种方式接近它实际上有很好的指针学习价值。
任何时候你在循环任何东西时挑选出不同的部分,而不是试图包含多个嵌套的 while
循环,每个循环都设计为 scan-forward 跳过或找到特定的 class 的字符,使用 state-loop 通常更有利,您可以在其中使用多个 flags 来跟踪不同的状态. (第 in-word 行读取字符,或在单词之间读取定界符或空格等。)。这样就不需要嵌套循环,您只需使用一个循环来遍历每个字符,根据您当前的状态做出相应的响应。
将其用于扫描您的字符串并挑选出每个以定界符 ';'
或空格终止的单词,并保留一个状态标志 int in;
以跟踪您是否in-word 读取字符 (in = 1;
) 或在单词之间处理空格和分隔符 (in = 0;
) 并使用 char *sp
作为 start-pointer 指向每个单词的开头, userInput
作为 end-pointer 指向当前正在读取的字符,你可以这样做:
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
作为标记,允许您循环遍历 main()
中数组中的指针,直到 [=达到 28=] 是因为您没有 return 使用的指针数量,无论是作为函数 return 还是通过指针参数)
一个使用 ';'
或空格作为分隔符解析来自 " 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++);
}
(注意: 包含 header ctype.h
是为了利用 isspace()
函数来测试空格而不是串在一起if()
语句直接检查 space
、'\t'
或 '\n'
。这通常是很好的做法。)
例子Use/Output
$ ./bin/split_ptr_arr3
'my'
'dog'
'has'
'fleas'
注意上面的输出中所有包含的空格都被删除了。
检查一下,如果您有任何问题,请告诉我。拆分字符串的方法有很多种,这只是一种常见的基本方法。