C:fscanf-第一个字符匹配时的无限循环

C:fscanf-第一个字符匹配时的无限循环,c,scanf,C,Scanf,我正在尝试使用fscanf解析文本(CSS)文件,并拉出与此模式匹配的所有语句: @导入“some/file/somewhere.css” 为此,我设置了以下循环: FILE *file = fopen(pathToSomeFile, "r"); char *buffer = (char *)malloc(sizeof(char) * 9000); while(!feof(file)) { // %*[^@] : Read and discard all characters up t

我正在尝试使用fscanf解析文本(CSS)文件,并拉出与此模式匹配的所有语句:

@导入“some/file/somewhere.css”

为此,我设置了以下循环:

FILE *file = fopen(pathToSomeFile, "r");
char *buffer = (char *)malloc(sizeof(char) * 9000);

while(!feof(file))
{
    // %*[^@] : Read and discard all characters up to a '@'
    // %8999[^;] : Read up to 8999 characters starting at '@' to a ';'.
    if(fscanf(file, "%*[^@] %8999[^;]", buffer) == 1)
    {
        // Do stuff with the matching characters here.
        // This code is long and not relevant to the question.
    }
}
只要文件中的第一个字符不是“@”,这种方法就可以完美地工作。(从字面上讲,CSS文件中第一个“@”字符前的一个空格将使代码运行正常。)

但是如果CSS文件中的第一个字符是“@”,那么我在调试器中看到的是一个无限循环——执行进入while循环,点击fscanf语句,但不进入“if”语句(fscanf失败),然后永远继续通过循环

我相信我的fscanf格式化程序可能需要一些调整,但我不确定如何继续。对于为什么会发生这种情况,有什么建议或解释吗


谢谢。

我不是
scanf
模式语法方面的专家,但我对你的解释是:

  • 匹配非“@”字符的非空序列,然后
  • 匹配最多8999个非空序列“;”字符
因此,是的,如果字符串以
“@”
开头,那么第一部分将失败


我认为,如果您用一些空格开始格式化字符串,那么
fscanf
将吃掉数据字符串中的任何前导空格,即简单地
%8999[^;]“
Oli已经说过fscanf失败的原因。由于故障是fscanf的正常状态,所以忙循环不是fscanf故障的结果,而是缺少对它的处理


即使您的格式正确(在您的特殊情况下),您也必须处理fscanf故障,因为您无法确保输入始终与格式匹配。实际上,您可以确保存在比匹配输入多得多的非匹配输入。

您的格式字符串执行以下操作:

  • 读取(并丢弃)1个或多个非
    @
    字符
  • 读取(并丢弃)0个或更多空白字符(由于格式字符串中的空格)
  • 读取并存储1到8999个非代码字符
不幸的是,没有格式说明符用于从用户定义的集合中读取“零个或多个”字符

如果您不关心一行上的多个@include语句,您可以将代码更改为读取一行(使用fgets),然后从中提取@include语句(如果第一个字符不等于
@
,您可以将当前格式字符串与sscanf一起使用,否则,您可以使用
sscanf(行),%8999[^;]”,缓冲区)


如果一行中有多个@include语句需要正确处理,则可以使用
getc
检查下一个要读取的字符,然后使用
ungetc
将其放回

您的字符串开头似乎缺少一个
%
。这是一个复制粘贴错误,还是一个bug?哎呀。在尝试诊断格式化程序的问题时,我删除了第一个%s。我已经把它放回了上面的代码中,但是它的存在并不能解决这个问题。这个问题既不是关于objective-c,也不是关于cocoa。因此,你应该删除这些标记。对Bryan不相关的建议:用设置几个变量和调用一两个函数来替换
//这段代码很长,…
,不要使用
scanf
来编写解析器。+1:这是一个很好的观点
fscanf
不是您想要的,除非您能绝对保证您的输入文件是100%格式良好的。您最好使用自定义解析器。谢谢Tilo。我知道我能应付失败。但我的问题是,输入文件是100%格式良好的;如果在我用fscanf('@'符号)查找的第一个字符之前有零个字符,那么它就失败了。@Bryan:我的答案(没有回答你原来的问题;)的要点是,如果你像你的问题一样在循环中使用fscanf,那么你不仅“可以”处理错误,而且“必须”处理它。因为——正如现实所表明的那样——你不能保证fscanf不会失败,即使你认为它不应该在你的输入上失败。如果您在提问时已经理解了这一点,那么像“为什么该输入行上的fscanf失败”这样的问题可能会更清楚,而不提及循环。您是正确的-
%8999[^;]“
将导致前导空格被丢弃。谢谢。我相信这已经在当前的格式化程序中捕获到:“%*[^@]%8999[^;]”对于一个不以“@”开头的文件,fscanf会正确地丢弃空白。@Bryan:的确如此。但是您当前的格式化程序不能使用以
“@”
开头的行,而我的建议可以!谢谢你,巴特。不幸的是,我确实关心单行上的多个@import语句,90%的情况下,该行会以“@”开头。如果真的没有办法让fscanf将第一个字符识别为匹配的字符,那么看起来我必须手动执行。