0

目前我正在尝试计算文件中有多少个数字。我在下面这样尝试:

while(fgets(fileContents, sizeof(fileContents)-1, fp))

        {

            if(fileContents[sizeof(fileContents)] == '\n')

                fileContents[sizeof(fileContents)] = '\0';



            if(fileContents[sizeof(fileContents)] == 32 )

                counter++;

            //parse numbers

            tokenPtr = strtok(fileContents," ");

            counter++;

        }

我有一串这样的数字:3 5 2 2 0 4 ... N 所以我不知道有多少个数字,所以我试着计算它们之间的空格,这就是你看到 ASCII 值 #32 的原因。有任何想法吗?(:

4

3 回答 3

0

strspn(3)我认为应该可以在这里完成大部分的跑腿工作。下面是一个如何计算字符串中初始正整数个数的示例:

#include <string.h>

int n_nums(const char *str)
{
    int n = 0;

    do {
        /* Skip over any whitespace */
        str += strspn(str, " \t\r\n");

        if (!strspn(str, "0123456789"))
            /* Not a number, we're done */
            break;

        /* Skip over the number. */
        str += strspn(str, "0123456789");

        /* Iff the next char is NUL or whitespace, we just
         * skipped over a valid number. */
        switch (*str) {
        case '\0':
        case ' ':
        case '\t':
        case '\r':
        case '\n':
            n++;
        }
    } while (*str);

    return n;
}

您应该能够将它与您开始处理的循环结合起来。

于 2020-03-26T23:06:11.193 回答
0

以下建议的代码:

  1. 实现一个两态状态机
  2. 执行所需的功能
  3. 干净地编译

现在,建议的代码:

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


int main( void )
{
    int count = 0;

    enum state { NOT_IN_NUMBER, IN_NUMBER };

    enum state currentState = NOT_IN_NUMBER;

    FILE *fp = fopen( "myInputFile.txt", "r" );
    if( !fp )
    {
        perror( "fopen failed" );
        exit( EXIT_FAILURE );
    }

    int ch;
    while( (ch = fgetc(fp)) != EOF )
    {
        //printf( "%d\n", ch ); //debugging
        if( isdigit( ch )  )
        {
            if( currentState == NOT_IN_NUMBER )
            {
                count++;
                currentState = IN_NUMBER;
            }
        }

        else
        {
            currentState = NOT_IN_NUMBER;
        }
    }

    fclose( fp );

    printf( "number of numbers: %d\n", count );
}

针对包含以下内容的文件运行:

3 5 2 2 0 4

输出是:

number of numbers: 6
于 2020-03-27T00:42:56.113 回答
0

ID:

a)获取文件的大小和内存映射文件(例如使用mmap()),所以它就像一个大数组uint8_t。或者,您可以通过任何其他方式将文件加载到内存中。

b) 对于数组中的每个字节uint8_t;与 0x30 异或。这使得数字字符成为 0x00 到 0x09 范围内的值,而其他所有值都是更大的值。

c) 对于数组中的每个字节uint8_t;如果它大于 0x09,则将其设置为 0x00,如果它不设置为 0x01。

d) 对于数组中的每个字节uint8_t;与下一个字节异或。此后,0x01 表示数字字符序列的开始或结束。

e) 对于数组中的每个字节uint8_t;将其值添加到计数器。这为您提供了(一个或多个)数字序列开始或结束的次数。通过将此计数除以 2(因为您只想要“开始”而不是“开始和结束”),您将得到您想要的答案。

请注意,所有这些步骤(除了第一个)都可以通过一个循环完成;并且对于使用 SIMD 进行优化都是微不足道的(对于您或编译器)(因此像 XOR 这样的单个操作可以并行处理多个字节 - 例如,对于 AVX-512,一次最多 64 个字节)。因此,它预计性能将由数据获取(如果存在“操作系统的文件系统缓存未命中”、CPU 缓存未命中等情况下的磁盘 IO)主导。

还; 这仅适用于简单的整数(例如字符串“$123,456,789.01”将被计为 4 个数字而不是一个数字);并且它不会检测/不会受到任何溢出的影响(例如,字符串“99999999999999999999999999999999999999999999999999999999999999999999999999”不会导致问题,但将被视为有效数字)。

最后; 这一切都假设字符编码是 ASCII 或 UTF-8。对于任何其他字符编码(EBCDIC、UTF-16、...),它将不起作用,需要修改/调整以适应。

于 2020-03-27T01:34:12.810 回答