有人可以告诉我如何在此字符串中逐个打印每个单词吗? 就像我有一个包含随机单词但具有固定模式的字符串,其中包含要打印的单词。但是,我的代码仅显示第一个单词“ apple”,然后停止。
这是字符串:
Svnsv am /apple/ rv dbndkbrb am /orange/ rv dbundib am /bestfruit/ rv drbrnboie am /watermelon/ rv
我想打印“苹果”,“橙色”,“最佳水果”,“西瓜”
char * v = b;
char * m;
char * p;
int t = 0;
int i = 0;
while(strstr(v, "am") != NULL){
m = strstr(v, "am");
//printf("%s\n",m);
p = strtok(m, "/");
p = strtok(NULL , "/");
printf("%s\n", p);
v+=5;
}
答案 0 :(得分:1)
因为您正在使用strtok
,所以只能找到第一个。
strtok
通过添加NUL字符来生成单独的标记,从而更改了标记化的字符串,因此,在循环结束时,您的字符串将看起来像"am \0apple\0 rv dbndkbrb am /orange/"
。当您将v
前进5个字符时,您不会远远超过刚刚处理过的内容,无法到达字符串的其余部分。
使用strtok
而不是使用strchr
,它会找到指定字符的下一个实例。用它来查找起始斜杠和结尾斜杠,并将结尾的斜杠替换为NUL。然后,您可以使用它(在由p2
表示的代码中)将v
正确放置在下一个要处理的文本块的开头。
while(strstr(v, "am") != NULL){
m = strstr(v, "am");
p = strchr(m, '/'); // Start
if (!p) {
v += 2;
continue;
}
p++;
p2 = strchr(p , '/'); // End
if (!p2) {
v = p;
continue;
}
*p2 = '\0';
printf("%s\n", p);
v = p2+1;
}
答案 1 :(得分:0)
使用putchar
可以像这样:
#include <stdio.h>
#include <string.h>
int main(void) {
char str[128] = "Svnsv am /apple/ rv dbndkbrb am /orange/ rv dbundib am /bestfruit/ rv drbrnboie am /watermelon/ rv";
char* p; // A help pointer for parsing the string
p = strstr(str, "am /"); // Find the first match
while (p)
{
p += 4; // Increment p to point just after "am /"
// print the word
putchar('"');
while (*p && *p != '/') putchar(*p++); // notice the increment of p
putchar('"');
putchar(' ');
if (p) p = strstr(p, "am /"); // find next match
}
return 0;
}
输出:
"apple" "orange" "bestfruit" "watermelon"
答案 2 :(得分:0)
由于使用strtok
,因此您只能找到第一个匹配项。试试:
char string[] = "Svnsv am /apple/ rv dbndkbrb am /orange/ rv dbundib am /bestfruit/ rv drbrnboie am /watermelon/ rv";
for (char *i = string; i != NULL; i = strstr(i, "am")) {
char *start;
char *end;
char *match;
if (start = strstr(i, "/")) {
if (end = strstr(start + 1, "/")) {
int start_index = start - string;
int end_index = end - string;
printf("%.*s\n", end_index - start_index - 1, string + start_index + 1);
}
}
i += 2;
}
答案 3 :(得分:0)
函数strtok()
通过在定界符的位置插入'\ 0'来修改原始字符串。 (请阅读strtok的文档。)当字符串被该'\ 0'截断时,下一个strstr
将找不到该模式。
这里是原始代码的略微修改版本。
#include <stdio.h>
#include <string.h>
int main(void) {
char str[] = "Svnsv am /apple/ rv dbndkbrb am /orange/ rv dbundib am /bestfruit/ rv drbrnboie am /watermelon/ rv";
char * v = str;
char * m;
char * p;
int t = 0;
int i = 0;
while(strstr(v, "am /") != NULL){
m = strstr(v, "am");
//printf("%s\n",m);
p = strtok(m, "/");
p = strtok(NULL , "/");
if(p != NULL)
{
printf("%s\n", p);
v = p + strlen(p)+1;
}
else
{
v+=5;
}
}
return 0;
}
答案 4 :(得分:0)
FWIW,这是一个使用GNU regex库的示例(取决于您的平台,该库可能不可用)。对于您尝试做的事情来说,这可能太过分了,但是它是其他人向您展示的方法的替代方法。根据您要匹配的模式的复杂程度,它可能会派上用场。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <regex.h>
int main( void )
{
/**
* Text we want to search.
*/
const char *text = "Svnsv am /apple/ rv dbndkbrb am /orange/ rv dbundib am /bestfruit/ rv drbrnboie am /watermelon/ rv";
/**
* The following pattern will isolate the strings between the '/'
* characters. ".*" matches any sequence of characters, so basically
* the pattern reads, "skip over any characters until we see an opening
* '/', then match everything up to the next '/', then repeat 3 more
* times".
*/
const char *ptn = ".*/(.*)/.*/(.*)/.*/(.*)/.*/(.*)/.*";
/**
* Regular expression type.
*/
regex_t regex;
/**
* Compile the regular expression
*/
if ( regcomp(®ex, ptn, REG_EXTENDED) != 0 )
{
fprintf( stderr, "regcomp failed on %s\n", ptn );
exit( 0 );
}
/**
* Set up an array to store the start and end positions of the
* matched substrings within text.
*/
fprintf( stdout, "Number of subexpressions: %zu\n", regex.re_nsub );
size_t matchCount = regex.re_nsub + 1;
regmatch_t pmatch[matchCount];
int ret;
/**
* Execute the regular expression, then print out the matched expressions
*/
if ( ( ret = regexec( ®ex, text, matchCount, pmatch, 0)) != 0 )
{
fprintf( stderr, "%s does not match %s, return code %d\n", text, ptn, ret );
}
else
{
fprintf( stdout, "Sucessful match\n" );
for ( size_t i = 0; i < matchCount; i++ )
{
if ( pmatch[i].rm_so >= 0 )
{
fprintf( stdout, "match %zu (start: %3lu; end: %3lu): %*.*s\n", i,
(unsigned long) pmatch[i].rm_so,
(unsigned long) pmatch[i].rm_eo,
(int) ( pmatch[i].rm_eo - pmatch[i].rm_so ),
(int) ( pmatch[i].rm_eo - pmatch[i].rm_so ),
text + pmatch[i].rm_so );
}
}
}
return 0;
}
这是输出:
Number of subexpressions: 4
Sucessful match
match 0 (start: 0; end: 98): Svnsv am /apple/ rv dbndkbrb am /orange/ rv dbundib am /bestfruit/ rv drbrnboie am /watermelon/ rv
match 1 (start: 10; end: 15): apple
match 2 (start: 33; end: 39): orange
match 3 (start: 56; end: 65): bestfruit
match 4 (start: 84; end: 94): watermelon
如果要复制匹配的字符串,则需要使用strncpy
并确保正确终止字符串:
char matched_string[MAX_STRING_LENGTH + 1] = {0};
...
size_t length = pmatch[1].rm_eo - pmatch[1].rm_so;
strncpy( matched_string, text + pmatch[1].rm_so, length );
/**
* Make sure string is 0 terminated
*/
matched_string[ length ] = 0;
答案 5 :(得分:0)
有人可以告诉我如何在此字符串中逐个打印每个单词吗?
请避免使用strtok()
,因为它会修改字符串并且不需要。
考虑如何解析输入字符串(好像是常量),一次解析一个子字符串。与您一样,查找"am"
,然后使用'/'
查找2个定界符strchr()
。如果找到所有内容,请更新输入字符串中的位置以再次查找,然后返回指向子字符串及其长度的指针。
const char *HL_parse(const char **v, const char *key, int delimiter, int *length) {
*length = 0;
char *token = strstr(*v, key);
if (token == NULL) {
return NULL;
}
char *start = strchr(token + strlen(key), delimiter);
if (start == NULL) {
return NULL;
}
start++;
char *end = strchr(start, delimiter);
if (end == NULL) {
return NULL;
}
*v = end + 1;
*length = (int)(end-start);
return start;
}
使用"%.*s"
打印子字符串。这样一来,最多可以打印不包含空字符的字符数组。
void HL_print_words(const char *v, const char *key, int delimiter) {
char *sep = "";
int length;
const char *token;
while ((token = HL_parse(&v, key, delimiter, &length)) != NULL) {
printf("%s\"%.*s\"%s", sep, length, token);
sep = " ";
}
printf("\n");
}
样品
int main(void) {
HL_print_words(
"Svnsv am /apple/ rv dbndkbrb am /orange/ rv dbundib am /bestfruit/ rv drbrnboie am /watermelon/ rv",
"am", '/');
}
输出
"apple" "orange" "bestfruit" "watermelon"