繁体   English   中英

从文本文件中提取字符串和整数并将它们放入数组C语言

[英]extract string and integers from text file and put them into array C language

我在这里遇到了问题,我无法弄清楚,所以任何帮助将不胜感激,我有一个文本文件,其中包含用逗号分隔的字符串和整数,我想提取整数并将它们放入数组中并提取字符串并将它们放入另一个数组中,这是文本文件示例:

1,2,dfds,dv,h,dfdd,wfdsf,e,3,4,yee,rss,a,6,8,5

这是代码:

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

#include "vector.h"

void readDataByDelimiter(const char* File, vector *v)
{
    FILE *myFile;
    myFile = fopen(File, "r");

    //read file into array
    int numberArray[16];
    int i;
    char b[100];

    for (i = 0; i < 16; i++)
    {
        fscanf(myFile, "%d,%c,",&numberArray[i] , &b[i]);
    }

    for (i = 0; i < 16; i++)
    {
        printf("Number is: %d\n\n", numberArray[i]);
        printf("Number is: %c\n\n", b[i]);
    }
}

要仅读取整数并跳过其他任何内容,您可以使用以下方法

#include <stdio.h>

int main()
{
    FILE * f = fopen("file.txt","r");
    int number;
    int res;
    while((res = fscanf(f, "%d,",&number)) != EOF){
        if(res == 1){
            printf("%d,", number);
        }
        else{
            fscanf(f,"%*[^,],");
        }
    }
    printf("\n");
    return 0;
}

这里当 res 为 1 时 - 您可以将读取的数字添加到数组中。 当 res 为 0 时-您需要跳过所有内容直到下一个,而当 fscanf 返回 EOF 时-这意味着文件结尾已丰富

编辑2

我真的不明白是什么阻止你扩展我的样本来做你想做的事。 这是稍微扩展的版本

#include <stdio.h>

int skip(FILE* f) {
    for(;;)
    {
        int res = fgetc(f);
        if(res == EOF)
            return 0;

        if(res == ',')
            return 1;
    }
}
int main()
{
    FILE * f = fopen("file.txt","r");
    int number;
    int res;
    while((res = fscanf(f, "%d,",&number)) != EOF) {
        if(res == 1) {
            printf("number - %d\n", number);
            //add number to array
        }
        else {
            char buffer[100];
            if(fscanf(f,"%99[^,]",buffer ) == 1)
            {
                printf("string - %s\n", buffer);
                //add buffer to string array
            }
            if(!skip(f))
                break;
        }
    }
    printf("\n");
    return 0;
}

我建议逐行读取,将每一行拆分为标记,检查每个标记是否为数字并将其添加到numArray ,否则添加到stringArray 请参阅以下代码,该代码使用strtok进行标记化并使用sscanf读取/检查数字。 希望能帮助到你。

void readDataByDelimiter(const char* File, char* stringArray[], int intArray[], int maxcount)
{
    FILE *myFile;
    myFile = fopen(File, "r");

    int intCount = 0;
    int stringCount = 0;

    char line[1000];
    while (myFile && fgets(line,sizeof(line),myFile)) {
        char* token = strtok(line, ",");
        while (token) {
            int num;
            if (sscanf(token, "%d", &num) == 1) {  // successfully scanned an int?
                if (intCount < maxcount) {
                    intArray[intCount++] = num;
                }
            }
            else {  // otherwise use as string
                if (stringCount < maxcount) {
                    stringArray[stringCount++] = strdup(token);
                }
            }
            token = strtok(NULL, ",");
        }
    }
}

int main() {

    int intArray[16] = { 0 };
    char* stringArray[16] = { NULL };

    readDataByDelimiter(DATAFILE, stringArray, intArray, 16);

    printf("numbers: \n");
    for (int i=0; intArray[i]; i++) {
        printf("%d ", intArray[i]);
    }
    printf("\nstrings: \n");
    for (int i=0; stringArray[i]; i++) {
        printf("%s ", stringArray[i]);
        free(stringArray[i]);
    }

}

输出:

numbers: 
1 2 3 4 6 8 5 
strings: 
dfds dv h dfdd wfdsf e yee rss a

由于您的示例输入不遵循整数-字符串-整数-字符串等的清晰模式,您可能希望首先将每个项目作为文本字符串读取,然后使用strtol将任何整数字符串转换为其相应的int值或类似的功能。

那你怎么做呢?

首先,您需要留出一个缓冲区来读取输入文本。

char buf[SIZE+1];

其中SIZE是最大预期字符串的长度。 请记住,在 C 中,字符串是一个字符值序列,后跟一个 0 值终止符。 字符串存储在char数组中(或wchar_t表示宽字符串),而不是单个char对象。

其次,我们需要将所有输入读取为 text ,但我们不想在该文本中包含,定界符或换行符。 因此,而不是使用%s ,我们将使用%[转换说明,这使我们能够指定的字符,我们希望输入的一部分。 我们还想确保我们读取的字符不会超过buf可以容纳的大小,因此我们还将在转换说明符中使用显式宽度。 不幸的是scanf要求将宽度硬编码为说明符的一部分(您不能像使用printf一样使用*并将宽度添加为额外参数)。 这是屁股的一大痛点,所以为了解决这个问题,我们必须用一个宏来发挥创意:

#define SIZE 20
#define FMT2(x) #x
#define FMT(x) "%" FMT2(x) "[^,\n]"

我们将像这样使用宏:

scanf( FMT(SIZE), buf );

宏展开后,将变成

scanf( "%20[^,\n]", buf );  // note no & operator on buf - not used for array expressions

这意味着,“从标准输入读取文本,直到我们看到逗号或换行符,或者我们已经读取了 20 个字符,然后将结果存储到buf ”。

最后,我们需要检查每个输入以查看它是否是一个整数字符串( "1""234"等)。 做到这一点的简单方法是使用strtol库函数,它将尝试将字符串转换为等效的整数。 它将返回一个指向不属于合法整数字符串的第一个字符的指针 - 如果该字符不是空格或字符串终止符,则输入不是有效整数:

char *chk;
int tmp = strtol( buf, &chk, 0 );
if ( !isspace( *chk ) && *chk != 0 )
{
  // tmp is not a valid integer string
}

以下是将所有这些组合在一起的独立程序:

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

#define SIZE 20
#define FMT2(x) #x
#define FMT(x) "%" FMT2(x)  "[^,\n]"

int main( void )
{
  int iValues[100];
  char sValues[100][SIZE+1];

  size_t iCount = 0;
  size_t sCount = 0;
  int    r = 1;

  char buf[SIZE+1] = {0};

  /**
   * Loop until one of the following is true:
   *
   *   - End of file or error on input
   *   - We see the string "end" (which will be included in the list of strings)
   *   - We've read 100 strings or integers
   */
  while ( strcmp( buf, "end" ) && r == 1 && iCount < 100 && sCount < 100 )
  {
    /**
     * The "%*c" tells scanf to read and discard the next character
     * from the input stream; if we don't do that, the trailing comma
     * or newline will foul up the next read and we'll get stuck in
     * an infinite loop.  
     */ 
    if ( ( r = scanf( FMT(SIZE) "%*c", buf )) == 1)
    {
      char *chk = 0;
      int tmp = (int) strtol( buf, &chk, 0 );
      if ( !isspace( *chk ) && *chk != 0 )
      {
        /**
         * The input string contains at least one non-numeric character,
         * so we add it to the sValues array.
         */
        strcpy( sValues[sCount++], buf );
      }
      else
      {
        /**
         * The input string is an integer, so we add it to the iValues
         * array
         */
        iValues[iCount++] = tmp;
      }
    }
  }

  for ( size_t i = 0; i < iCount; i++ )
    printf( "iValues[%zu] = %d\n", i, iValues[i] );

  for ( size_t i = 0; i < sCount; i++ )
    printf( "stringValues[%zu] = %s\n", i, sValues[i] );

  return 0;
}

在您的示例输入上运行,输出为:

$ ./delim
1,2,dfds,dv,h,dfdd,wfdsf,e,3,4,yee,rss,a,6,8,5
iValues[0] = 1
iValues[1] = 2
iValues[2] = 3
iValues[3] = 4
iValues[4] = 6
iValues[5] = 8
iValues[6] = 5
stringValues[0] = dfds
stringValues[1] = dv
stringValues[2] = h
stringValues[3] = dfdd
stringValues[4] = wfdsf
stringValues[5] = e
stringValues[6] = yee
stringValues[7] = rss
stringValues[8] = a

此代码未处理的一个问题 - 如果您输入的字符串长于缓冲区可容纳的大小,它将被拆分为两个(或多个)字符串(由于%*c说明符而丢弃一个字符) :

$ ./delim
abcdefghijklmnopqrstuvwxyz
stringValues[0] = abcdefghijklmnopqrst
stringValues[1] = vwxyz

你会想要决定如何处理这个问题,但现在这应该会让你继续前进。

暂无
暂无

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

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