【问题标题】:Why scanf() can't filter double quatation mark, although set format to [A-Za-z]为什么 scanf() 不能过滤双引号,尽管将格式设置为 [A-Za-z]
【发布时间】:2015-02-08 09:36:20
【问题描述】:

我试图只提取除句子中其他字符之外的字母词。

为此,我使用两个 scanf() 如下所示。

scanf("%s", word);
sscanf(word, "%[A-Za-z]", word);

问题是,没有删除双引号,尽管我将格式设置为 %[A-Za-z] 然而奇怪的是,如果这个标记在单词的最后一个位置上,它就被移除了。

有人知道原因吗?

测试用例
- “迪士尼乐园
- 左。”

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

#define MAX_WORD    128

int main(int argc, char* argv[]) {
    char word[MAX_WORD];

    /* Read all of contents */
    while (EOF != scanf("%s", word)) {
        printf("origin word: %s\n", word);
        sscanf(word, "%[A-Za-z\"]s", word);
        printf("transformed: %s\n", word);

    }   
 }

【问题讨论】:

  • 呃...目标可以和sscanf的读取字符串相同吗?看起来很吓人……这里有没有过分热情的语言律师?
  • 您是否希望sscanf() 跳过第一个引号?我认为它会在不读取任何内容的情况下返回(保持word 的内容不变)。
  • @KarolyHorvath,它可能是安全的,但我只是基于我如何实现sscanf,至少对于这个特定的用例:-)跨度>
  • 哦,很抱歉我的内容出现了一些错误。我已经修改过了。而且,我的目的是仅使用 sscanf() 从标准输入中提取一个字母。我只想知道是我的错误使用还是sscanf的限制造成的。
  • 如果字符串包含 -%[ 的行为是实现定义的。所以这段代码依赖于你的系统所拥有的任何 libc 实现,而不是标准 C。

标签: c string scanf standard-library


【解决方案1】:

由于 句号, 而不是引号,因此它正在剥离第二行的末尾,因此它同时剥离了句点 引号。

您已要求它扫描由字母 A-Za-z^" 组成的字符串,因此句点的存在会导致它在该点停止。

我不确定你是否完全理解它是如何工作的。它不会为您提供字符串中与您指定的字符匹配的所有字符,而丢弃其余字符。相反,它将接受直到第一个有效字符的字符,然后丢弃其他所有字符。如果你输入一些完全有效的字符,中间有一个无效的字符,你可以看到这一点:

abcdefg.hijklmnop
origin word: abcdefg.hijklmnop
transformed: abcdefg

由此可见,它在第一个无效字符处停止,而不是仅仅去除无效字符。

如果你想要一个只有匹配字符的字符串,你可以使用类似的东西:

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

#define MAX_WORD 128

static void strip(char *word, char *allow) {
    char *d = word;
    while (*word != '\0') {
        if (strchr (allow, *word) != NULL)
            *d++ = *word;
        word++;
    }
    *d = '\0';
}

int main (void) {
    char word[MAX_WORD];

    while (EOF != scanf ("%s", word)) {
        printf("origin word: %s\n", word);
        strip (word, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz^\"");
        printf("transformed: %s\n", word);
    }
}

并且,使用一组样本运行:

"Disneyland
origin word: "Disneyland
transformed: "Disneyland

Left."
origin word: Left."
transformed: Left"

dvsdhjshhvsdf6553785365^%%$$@@#*&*&mjdvsdddhvjhdfvb
origin word: dvsdhjshhvsdf6553785365^%%$$@@#*&*&mjdvsdddhvjhdfvb
transformed: dvsdhjshhvsdf^mjdvsdddhvjhdfvb

【讨论】:

  • 感谢您的关注和来源。但我认为,句号不是跳过句末双引号的原因。例如 [A-Za-z] 格式的 sscanf 可以将 [Left"] 更改为 [Left]。
  • @joejo,扫描[Left"] 将完全失败,因为[ 无效。扫描Left"(假设[] 是您评论中的分隔符)将删除",因为它是第一个无效字符(它也拒绝扫描字符串的其余部分,但这并不明显,因为" 是最后一个特点)。扫描Left.xyzzy 将停止在.,同时丢弃xyzzy。我建议你阅读fscanf doco,它的行为不像你想象的那样。它会在 first 无效字符处停止扫描,我已经更新了答案以使其更清晰。
【解决方案2】:
        sscanf(word, "%[A-Za-z\"]s", word);

编程语言 - C - sscanf 函数 - 描述

…如果复制发生在重叠的对象之间,则行为是 未定义。

因此,您对sscanf 的使用无效。也就是说,即使使用正确,您的测试用例的结果也是可以预期的; paxdiablo 的答案中嵌入了解释。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多