简体   繁体   English

使用 sscanf 读取带空格的字符串

[英]Reading a string with spaces with sscanf

For a project I'm trying to read an int and a string from a string.对于一个项目,我试图从一个字符串中读取一个 int 和一个字符串。 The only problem is sscanf() appears to break reading an %s when it sees a space.唯一的问题是sscanf()在看到空格时似乎会中断读取%s Is there anyway to get around this limitation?有没有办法绕过这个限制? Here's an example of what I'm trying to do:这是我正在尝试做的一个例子:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv) {
    int age;
    char* buffer;
    buffer = malloc(200 * sizeof(char));
    sscanf("19 cool kid", "%d %s", &age, buffer);

    printf("%s is %d years old\n", buffer, age);
    return 0;
}

What it prints is: cool is 19 years old where I need cool kid is 19 years old .它打印的是: cool is 19 years old where I need cool kid is 19 years old Does anyone know how to fix this?有谁知道如何解决这一问题?

以下行将开始读取一个数字( %d ),然后是与制表符或换行符( %[^\\t\\n] )不同的任何内容。

sscanf("19 cool kid", "%d %[^\t\n]", &age, buffer);

You want the %c conversion specifier, which just reads a sequence of characters without special handling for whitespace.您需要%c转换说明符,它只读取一个字符序列而无需对空格进行特殊处理。

Note that you need to fill the buffer with zeroes first, because the %c specifier doesn't write a nul-terminator.请注意,您需要先用零填充缓冲区,因为%c说明符不写入空终止符。 You also need to specify the number of characters to read (otherwise it defaults to only 1):您还需要指定要读取的字符数(否则默认仅为 1):

memset(buffer, 0, 200);
sscanf("19 cool kid", "%d %199c", &age, buffer);

If you want to scan to the end of the string (stripping out a newline if there), just use:如果你想扫描到字符串的末尾(如果有的话,去掉一个换行符),只需使用:

char *x = "19 cool kid";
sscanf (x, "%d %[^\n]", &age, buffer);

That's because %s only matches non-whitespace characters and will stop on the first whitespace it finds.那是因为%s只匹配非空白字符并且会在它找到的第一个空白处停止。 The %[^\\n] format specifier will match every character that's not (because of ^ ) in the selection given (which is a newline). %[^\\n]格式说明符将匹配给定选择(这是一个换行符)中不是(因为^ )的每个字符。 In other words, it will match any other character.换句话说,它将匹配任何其他字符。


Keep in mind that you should have allocated enough space in your buffer to take the string since you cannot be sure how much will be read (a good reason to stay away from scanf/fscanf unless you use specific field widths).请记住,您应该在缓冲区中分配足够的空间来获取字符串,因为您无法确定将读取多少(除非使用特定字段宽度,否则这是远离scanf/fscanf一个很好的理由)。

You could do that with:你可以这样做:

char *x = "19 cool kid";
char *buffer = malloc (strlen (x) + 1);
sscanf (x, "%d %[^\n]", &age, buffer);

(you don't need * sizeof(char) since that's always 1 by definition). (你不需要* sizeof(char)因为它的定义总是1 )。

Since you want the trailing string from the input, you can use %n (number of characters consumed thus far) to get the position at which the trailing string starts.由于您想要来自输入的尾随字符串,您可以使用%n (到目前为止消耗的字符数)来获取尾随字符串开始的位置。 This avoids memory copies and buffer sizing issues, but comes at the cost that you may need to do them explicitly if you wanted a copy.这避免了内存副本和缓冲区大小问题,但代价是如果您想要副本,您可能需要明确地执行这些操作。

const char *input = "19  cool kid";
int age;
int nameStart = 0;
sscanf(input, "%d %n", &age, &nameStart);
printf("%s is %d years old\n", input + nameStart, age);

outputs:输出:

cool kid is 19 years old

I guess this is what you want, it does exactly what you specified.我想这就是您想要的,它完全符合您的要求。

#include<stdio.h>
#include<stdlib.h>

int main(int argc, char** argv) {
    int age;
    char* buffer;
    buffer = malloc(200 * sizeof(char));
    sscanf("19 cool kid", "%d cool %s", &age, buffer);
    printf("cool %s is %d years old\n", buffer, age);
    return 0;
}

The format expects: first a number (and puts it at where &age points to), then whitespace (zero or more), then the literal string "cool", then whitespace (zero or more) again, and then finally a string (and put that at whatever buffer points to).该格式要求:首先是一个数字(并将其放在 &age 指向的位置),然后是空格(零个或多个),然后是文字字符串“cool”,然后又是空格(零个或多个),最后是一个字符串(和把它放在任何缓冲区指向的地方)。 You forgot the "cool" part in your format string, so the format then just assumes that is the string you were wanting to assign to buffer.您忘记了格式字符串中的“cool”部分,因此格式仅假定这是您想要分配给缓冲区的字符串。 But you don't want to assign that string, only skip it.但是您不想分配该字符串,只需跳过它。

Alternative, you could also have a format string like: "%d %s %s", but then you must assign another buffer for it (with a different name), and print it as: "%s %s is %d years old\\n".或者,你也可以有一个格式字符串,如:“%d %s %s”,但你必须为它分配另一个缓冲区(使用不同的名称),并将其打印为:“%s %s is %d years旧\\n”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM