简体   繁体   English

C:在scanf中匹配单个空格

[英]C: Matching a single space in a scanf

I just want to force a scanf to read a single space and then store the rest of the string until a comma is found in a variable. 我只想强制scanf读取单个空格,然后存储字符串的其余部分,直到在变量中找到逗号为止。 I cannot do it like this: 我不能这样做:

char content[100];
fscanf(f, " %[^,\n],", content);

because I don't want content to be set if there is a pending '\\n' . 因为如果有待处理的'\\n'我不希望设置content Is there a way to scape the whitespace? 有没有办法摆脱空白?

The workaround I've found so far: 我到目前为止发现的解决方法:

char space;
fscanf(f, "%1[^\n]%[^,\n],", &space, content);

Sorry for the silly question and thank you in advance. 很抱歉这个愚蠢的问题,谢谢您。

I'm supposing that the code you presented expresses your intent better than your words, which don't correspond on the details. 我想您提供的代码比语言更能表达您的意图,而言语与细节并不一致。 Inasmuchas you say ... 你说的Inasmuchas ...

The workaround I've found so far: 我到目前为止发现的解决方法:

 char space; fscanf(f, "%1[^\\n]%[^,\\n],", &space, content); 

... I conclude that that code seems to you to do what you want, and I infer that you designate it a "workaround" instead of a wholly satisfactory solution on account of the need for the space variable to be involved. ...我得出结论,该代码在您看来可以完成您想做的事情,并且我推断您将其指定为“替代方法”,而不是因为涉及到space变量而导致的完全令人满意的解决方案。

Indeed, it's worse than that: whenever scanf() successfully matches the first field, it invokes undefined behavior by overrunning the bounds of space . 确实,这比这更糟:每当scanf()成功匹配第一个字段时,它都会通过超越space的边界来调用未定义的行为。 That happens because the [ field descriptor matches nonempty strings , which have a terminator after their content. 发生这种情况是因为[段描述符与非空字符串匹配,该字符串的内容后有一个终止符。 But the good news is that getting rid of the need for the extra variable, which you seem to want to do anyway, will solve that problem, too. 但是好消息是,摆脱对多余变量的需求(您似乎仍然想这样做)也将解决该问题。

The easiest way to do that would be to apply the assignment-suppression modifier ( * ) to the corresponding field descriptor: 最简单的方法是将分配抑制修饰符( * )应用于相应的字段描述符:

fscanf(f, "%*1[^\n]%[^,\n],", content);

Do be sure to check the return value to determine whether anything was assigned to content . 确保检查返回值以确定是否为content分配了任何content It will be 1 if a non-empty string was matched and assigned to content (after matching but not assigning the leading newline), -1 if the file f was initially positioned at its end or if an I/O error occurs, or 0 if a matching failure occurs before assigning content . 这将是1 ,如果一个非空字符串被匹配并分配给content (匹配但不分配龙头换行符之后), -1 ,如果该文件f最初定位在其端部或如果发生I / O错误,或0如果在分配content之前发生匹配失败。

Update : 更新

As @chux observed, the scanf format above does nothing to protect against overrunning the bounds of content in the event that the corresponding data is wider than it can accommodate. 如@chux观察到的, scanf格式以上什么都不做,以防止超越的界限content在事件相应的数据宽度大于它可以容纳。 Since you're declaring it as an array of 100 char , it can accommodate up to 99 characters plus a terminator, which you can ensure is not overrun like so: 由于您将其声明为100个char的数组,因此它最多可以容纳99个字符以及一个终止符,您可以确保它不会像下面这样被溢出:

fscanf(f, "%*1[^\n]%99[^,\n],", content);

That leaves you with the possibility that scanning stops before either a newline or a comma is seen, however, and the return value will not help you distinguish that case from a wholly successful scan. 但是,这使您有可能在看到换行符或逗号之前停止扫描,并且返回值将无法帮助您将该情况与完全成功的扫描区分开。 In that event, the next scan will yield a matching failure (supposing that the same format is used). 在这种情况下, 下一次扫描将产生匹配失败(假设使用相同的格式)。 There is more than one way to address that, but you might consider omitting the trailing comma from your format, and instead checking for a comma and consuming it separately via a call to fgetc() . 有多种解决方法,但是您可以考虑省略格式中的尾部逗号,而是检查逗号并通过调用fgetc()单独使用它。

And you have to use fscanf() because...? 而且您必须使用fscanf()是因为...?

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

size_t myScan (
    const char * string,
    char * outBuffer,
    size_t outBufferMax
) {
    // No string
    if (!string) return 0;
    // First char not a space
    if (string[0] != ' ') return 0;
    // Find semicolon
    size_t size = 0;
    while (string[size + 1] != 0 && string[size + 1] != ';') size++;
    // Doesn't fit into buffer!
    if (size > outBufferMax) return 0;

    memcpy(outBuffer, &string[1], size);
    return size;
}


int main ( ) {
    size_t size = 0;
    char content[100] = { 0 };
    char * test = " Hello World; Test Test; Foobar!";

    size = myScan(test, content, sizeof(content));
    printf("###%.*s###\n", (int)size, content);

    size = myScan(&test[6], content, sizeof(content));
    printf("###%.*s###\n", (int)size, content);

    size = myScan(&test[13], content, sizeof(content));
    printf("###%.*s###\n", (int)size, content);

    size = myScan(&test[24], content, sizeof(content));
    printf("###%.*s###\n", (int)size, content);

    // No position with a space in front!
    size = myScan(&test[22], content, sizeof(content));
    printf("###%.*s###\n", (int)size, content);


    return 0;
}

Output: 输出:

###Hello World###
###World###
###Test Test###
###Foobar!###
######

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

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