确定文本文件C中的数字或字符

确定文本文件C中的数字或字符,c,gcc,text-files,file-handling,C,Gcc,Text Files,File Handling,我有一个文本文件,里面有以下数字和字符 36@xL!?\8 28?&gt;\4 42&lt;pX%7 37@#5 31kL%^?&gt;\&lt;#%5 现在,我想得到第一个36的整数,再减去最后一个8的整数。我想一行一行地做这件事。你想读这行,解析开头和结尾的数字,然后把它们转换成整数。下面是一个简单的例子: #include <stdio.h> #include <ctype.h> #include <stdlib.h>

我有一个文本文件,里面有以下数字和字符

36@xL!?\8
28?&gt;\4
42&lt;pX%7
37@#5
31kL%^?&gt;\&lt;#%5

现在,我想得到第一个36的整数,再减去最后一个8的整数。我想一行一行地做这件事。

你想读这行,解析开头和结尾的数字,然后把它们转换成整数。下面是一个简单的例子:

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

main()
{
    FILE *file = fopen("input.txt", "r");
    char line[256];

    while (fgets(line, sizeof(line), file))
    {
    char num[15];
    int firstNumber = 0;
    int secondNumber = 0;

    line[strcspn(line, "\r\n")] = 0;

    for (int x = 0; x < 256; x++)
    {
        if (isdigit(line[x]))
        {
            num[x] = line[x];
        } 
        else 
        {
            num[x] = 0;
            break;
        }
    }        
    firstNumber = atoi(num);

    int length = strlen(line);
    int ndx = 0;
    while (length >=0 && isdigit(line[length - 1]))
    {
        num[ndx] = line[length - 1];
        ndx++;
        length--;
    }
    num[ndx] = 0;
    secondNumber = atoi(num);

    printf("%d - %d = %d\n", firstNumber, secondNumber, firstNumber - secondNumber);
    }

    fclose(file);
}
#包括
#包括
#包括
#包括
main()
{
FILE*FILE=fopen(“input.txt”,“r”);
字符行[256];
while(fgets(行、sizeof(行)、文件))
{
字符数[15];
int firstNumber=0;
int secondNumber=0;
行[strcspn(行,“\r\n”)]=0;
对于(int x=0;x<256;x++)
{
if(isdigit(第[x]行))
{
num[x]=行[x];
} 
其他的
{
num[x]=0;
打破
}
}        
firstNumber=atoi(num);
整数长度=strlen(直线);
int ndx=0;
while(长度>=0&&isdigit(行[length-1]))
{
num[ndx]=行[length-1];
ndx++;
长度--;
}
num[ndx]=0;
secondNumber=atoi(num);
printf(“%d-%d=%d\n”,firstNumber,secondNumber,firstNumber-secondNumber);
}
fclose(文件);
}

对于作为问题的一部分发布的文件,您已经有了一个很好的答案,但是,如果您的文本行在表示负号值的数字之前包含一个
'-'
符号,则
第一个-最后一个
的结果将不正确。所有C字符串到整数的转换都将在要转换的值之前接受一个前导的
+/-
,表示正数或负数。如果您的输入可以包含负值,则需要保留
'-'
符号,方法是将其与要转换的数字一起包含。例如,如果您的输入文件是:

36@xL!?\-8
28?&gt;\4
-42&lt;pX%7
37@#-5
31kL%^?&gt;\&lt;#%5
如果文件中的整数值为
-8、-42
-5
,则答案会大不相同。现在,如果基于您的特定赋值,这不是一种可能性,那么您可以跳过保存
'-'
,但是对于将读取世界文本转换为有符号值来说,这是至关重要的

查找要在字符串中转换的有符号数字的开头的一种方法是简单地向前扫描字符串(类似于
strpbrk()
所做的),查找开头数字或
'-'
(以先出现的为准)。如果先出现
“-”
,则检查下一个字符是否为数字。你可以用一个简单的循环来完成,例如

/** scan forward in 'p' to find beginning of next valid signed integer.
 *  returns pointer to beginning of signed int on success, NULL otherwise.
 */
const char *nextdigit (const char *p)
{
    while (*p) {
        /* if digit or +/- followed by a digit */
        if (isdigit(*p) ||
            ((*p == '-' || *p == '+') && isdigit(*(p + 1))))
            return p;
        p++;
    }
    return NULL;
}
一旦您找到一个数字的开头,那么您就需要使用一个函数来检查转换过程中的错误
atoi()
为转换提供零诊断,并将静默返回
0
作为转换
atoi(“我的奶牛”)的有效数字您将无法指示是否实际转换了数字,或者结果是否超过所有整数类型的存储大小
atoi()
即使提供了200位字符串作为输入,也不会发出任何错误。至少,使用将至少提供有效转换是否发生的
sscanf
true/false
sscanf
,或者更好地使用提供转换完整错误报告的
strtol

例如,您可以编写一个简短的函数,获取指向字符串的指针的地址,使用上面的
nextdigit()
函数,然后使用
strtol
完全验证结果,设置
errno
在调用程序中验证任何错误并返回整数转换的结果(或
0
出错)如下所示:

/** returns next integer in string pointed to by p, or sets errno and returns
 *  zero on error.
 */
int getnextint (char **p)
{
    int nextint = 0;

    errno = 0;
    if ((*p = (char*)nextdigit(*p))) {
        char *endptr;
        long tmp = strtol (*p, &endptr, 0);

        if (*p == endptr) { /* validate digits converted */
            fputs ("error: no digits converted.\n", stderr);
            errno = EINVAL;
        }
        else if (errno)     /* validate conversion */
            fputs ("error: over/underflow occurred.\n", stderr);
        /* validate tmp is in range of integer */
        else if (INT_MIN <= tmp && tmp <= INT_MAX)
            nextint = tmp;
        else {
            fputs ("error: value exceeds range of int.\n", stderr);
            errno = ERANGE;
        }
        *p = (char*)nextdigit(endptr);
    }
    else
        errno = EINVAL;     /* if no digits found, set EINVAL */

    return nextint;
}
示例输入文件

您的原始输入文件:

$ cat dat/last-first.txt
36@xL!?\8
28?&gt;\4
42&lt;pX%7
37@#5
31kL%^?&gt;\&lt;#%5
另一个是负值和额外的外线:

$ cat dat/last-first2.txt
36@xL!?\-8
28?&gt;\4
-42&lt;pX%7
Nothing to see!
37@#-5
31kL%^?&gt;\&lt;#%5
示例使用/输出

$ ./bin/fgets_strtol_any_last-first dat/last-first.txt
36@xL!?\8            :   36 -  8 =  28
28?&gt;\4            :   28 -  4 =  24
42&lt;pX%7           :   42 -  7 =  35
37@#5                :   37 -  5 =  32
31kL%^?&gt;\&lt;#%5  :   31 -  5 =  26
在具有负值和无关行的文件上运行时:

$ ./bin/fgets_strtol_any_last-first dat/last-first2.txt
36@xL!?\-8           :   36 - -8 =  44
28?&gt;\4            :   28 -  4 =  24
-42&lt;pX%7          :  -42 -  7 = -49
0 integer(s) in: 'Nothing to see!'
37@#-5               :   37 - -5 =  42
31kL%^?&gt;\&lt;#%5  :   31 -  5 =  26

从不同文件之间的减法结果可以看出,在转换签名值时,是否保留领先的<代码> -<代码>有很大的区别。


仔细检查一下,如果有其他问题,请告诉我。

使用
fgets
sscanf
,或者只使用
fscanf
@lower我知道这些功能,但我想知道如何使用它们functions@lurker我想要得到第一个和最后一个整数,我想要忽略m中的字符/符号“我知道这些函数”-->发布您尝试过的代码,否则您只是要求其他人完成您的工作。然后使用
fgets
将每一行读入缓冲区,然后使用
strtol
(使用
endptr
参数向下遍历字符串,将数字转换为整数)好主意!thanksHow会被解释成
45
还是
-45
$ ./bin/fgets_strtol_any_last-first dat/last-first2.txt
36@xL!?\-8           :   36 - -8 =  44
28?&gt;\4            :   28 -  4 =  24
-42&lt;pX%7          :  -42 -  7 = -49
0 integer(s) in: 'Nothing to see!'
37@#-5               :   37 - -5 =  42
31kL%^?&gt;\&lt;#%5  :   31 -  5 =  26