Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C-读取非字母字符作为单词边界_C_Regex_String - Fatal编程技术网

C-读取非字母字符作为单词边界

C-读取非字母字符作为单词边界,c,regex,string,C,Regex,String,我试图解析一个文本文件,并将每个不同的单词添加到一个哈希表中,单词作为键,频率作为值。问题在于阅读部分:该文件是一个非常大的“普通”文本文件,其中包含标点符号和特殊字符。我想将所有读入的非字母字符视为单词边界。我有一些基本的想法: char buffer[128]; while(fscanf(fp, "%127[A-Za-z]%*c", buffer) == 1) { printf("%s\n", buffer); memset(buffer, 0, 128); } 然而,

我试图解析一个文本文件,并将每个不同的单词添加到一个哈希表中,单词作为键,频率作为值。问题在于阅读部分:该文件是一个非常大的“普通”文本文件,其中包含标点符号和特殊字符。我想将所有读入的非字母字符视为单词边界。我有一些基本的想法:

char buffer[128];
while(fscanf(fp, "%127[A-Za-z]%*c", buffer) == 1) {
    printf("%s\n", buffer); 
    memset(buffer, 0, 128); 
}

然而,每当它实际命中一个非字母顺序的字符并加上空格时(例如,“the,cat was(brown)”就会被读入“the cat was”)。我知道这段代码有什么问题,但我不知道如何解决。我是否最好只阅读整行内容并手动进行解析?我正在尝试
scanf
,因为我觉得这是一个很好的迷你正则表达式的候选者,您可以使用格式字符串

除了评论中提到的方法之外,还有另一种方法。我不知道这样是否更好。您可以使用
fgets
从文件中读取行,然后使用
strtok\u r
POSIX函数标记该行。这里,
r
意味着函数是可重入的,这使得它是线程安全的。但是,您必须知道文件中行的最大长度

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

#define MAX_LEN 100

// in main

char line[MAX_LEN];
char *token;
const char *delim = "!@#$%^&*";  // all special characters
char *saveptr;       // for strtok_r 
FILE *fp = fopen("myfile.txt", "r");

while(fgets(line, MAX_LEN, fp) != NULL) {
    for(; ; line = NULL) {
        token = strtok_r(line, delim, &saveptr);
        if(token == NULL)
            break;
        else {
            // token is a string.
            // process it
        }   
    }    
}

fclose(fp);
#包括
#包括
#定义最大长度100
//大体上
字符行[MAX_LEN];
字符*令牌;
const char*delim=“!@$%^&*”;//所有特殊字符
char*saveptr;//斯特尔托克大学
FILE*fp=fopen(“myfile.txt”、“r”);
while(fgets(直线,最大长度,fp)!=NULL){
对于(;;行=NULL){
令牌=strtok_r(行、delim和saveptr);
if(标记==NULL)
打破
否则{
//令牌是一个字符串。
//处理它
}   
}    
}
fclose(fp);

strtok\u r
修改它的第一个参数
,因此,如果出于其他目的需要,您应该保留它的副本。

除了注释中提到的方法之外,还有另一种方法。我不知道这样是否更好。您可以使用
fgets
从文件中读取行,然后使用
strtok\u r
POSIX函数标记该行。这里,
r
意味着函数是可重入的,这使得它是线程安全的。但是,您必须知道文件中行的最大长度

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

#define MAX_LEN 100

// in main

char line[MAX_LEN];
char *token;
const char *delim = "!@#$%^&*";  // all special characters
char *saveptr;       // for strtok_r 
FILE *fp = fopen("myfile.txt", "r");

while(fgets(line, MAX_LEN, fp) != NULL) {
    for(; ; line = NULL) {
        token = strtok_r(line, delim, &saveptr);
        if(token == NULL)
            break;
        else {
            // token is a string.
            // process it
        }   
    }    
}

fclose(fp);
#包括
#包括
#定义最大长度100
//大体上
字符行[MAX_LEN];
字符*令牌;
const char*delim=“!@$%^&*”;//所有特殊字符
char*saveptr;//斯特尔托克大学
FILE*fp=fopen(“myfile.txt”、“r”);
while(fgets(直线,最大长度,fp)!=NULL){
对于(;;行=NULL){
令牌=strtok_r(行、delim和saveptr);
if(标记==NULL)
打破
否则{
//令牌是一个字符串。
//处理它
}   
}    
}
fclose(fp);

strtok\u r
修改其第一个参数
,因此如果出于其他目的需要,您应该保留一份副本。

建议使用
isalpha()
fgetc()
和一个简单的状态机

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

int AdamRead(FILE *inf, char *dest, size_t n) {
  int ch;
  do {
    ch = fgetc(inf);
    if (ch == EOF) return EOF;
  } while (!isalpha(ch));

  assert(n > 1);
  n--;  // save room for \0
  while (n-- > 0) {
    *dest++ = ch;
    ch = fgetc(inf);
    if (!isalpha(ch)) break;
  }

  ungetc(ch, inf);  // Add this is something else may need to parse `inf`.
  *dest = '\0';
  return 1;
}

char buffer[128];
while(AdamRead(fp, buffer, sizeof buffer) == 1) {
  printf("%s\n", buffer); 
}
#包括
#包括
#包括
int AdamRead(文件*inf,字符*dest,大小\u t n){
int-ch;
做{
ch=fgetc(inf);
如果(ch==EOF)返回EOF;
}而(!isalpha(ch));
断言(n>1);
n--;//为\0保存空间
而(n-->0){
*dest++=ch;
ch=fgetc(inf);
如果(!isalpha(ch))断裂;
}
ungetc(ch,inf);//添加这是解析'inf'可能需要的其他内容。
*dest='\0';
返回1;
}
字符缓冲区[128];
while(AdamRead(fp,buffer,sizeof buffer)==1){
printf(“%s\n”,缓冲区);
}

注意:如果您想走
%127[A-Za-z]%*[^A-Za-z]“
路线,代码可能需要以一次性
fscanf(fp,“*[^A-Za-z]”开头
处理前导非字母。

建议使用
isalpha()
fgetc()
和简单状态机

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

int AdamRead(FILE *inf, char *dest, size_t n) {
  int ch;
  do {
    ch = fgetc(inf);
    if (ch == EOF) return EOF;
  } while (!isalpha(ch));

  assert(n > 1);
  n--;  // save room for \0
  while (n-- > 0) {
    *dest++ = ch;
    ch = fgetc(inf);
    if (!isalpha(ch)) break;
  }

  ungetc(ch, inf);  // Add this is something else may need to parse `inf`.
  *dest = '\0';
  return 1;
}

char buffer[128];
while(AdamRead(fp, buffer, sizeof buffer) == 1) {
  printf("%s\n", buffer); 
}
#包括
#包括
#包括
int AdamRead(文件*inf,字符*dest,大小\u t n){
int-ch;
做{
ch=fgetc(inf);
如果(ch==EOF)返回EOF;
}而(!isalpha(ch));
断言(n>1);
n--;//为\0保存空间
而(n-->0){
*dest++=ch;
ch=fgetc(inf);
如果(!isalpha(ch))断裂;
}
ungetc(ch,inf);//添加这是解析'inf'可能需要的其他内容。
*dest='\0';
返回1;
}
字符缓冲区[128];
while(AdamRead(fp,buffer,sizeof buffer)==1){
printf(“%s\n”,缓冲区);
}

注意:如果您想走
%127[A-Za-z]%*[^A-Za-z]“
路线,代码可能需要以一次性
fscanf(fp,“*[^A-Za-z]”开头
用于处理前导非字母。

%127[A-Za-z]%*[^A-Za-z]“
作为一个简单的解决方案。谢谢!这就是我所需要的。使用
while(fscanf(fp,“%*[^A-Za-z]”),fscanf(fp,“%127[A-Za-z]”,buffer)==1{
可以很好地处理前面可能有非字母的第一个字母组。
%127[A-Za-z]*[^A-Za-z]”
没有。这两种方法都能很好地处理最后一个字母组,可以选择后面跟非字母。逗号运算符的使用很好:)
%127[A-Za-z]*[^A-Za-z]“
作为一种简单的修复方法。谢谢!这就是我所需要的。使用
while(fscanf(fp,%*[^A-Za-z]),fscanf(fp,“%127[A-Za-z]”,buffer)==1{
可以很好地处理前面可能有非字母的第一个字母组。
%127[A-Za-z]%*[^A-Za-z]“
不能。这两种方法都可以很好地处理后面可能有非字母的最后一个字母组。逗号运算符的使用很好:)为什么我们需要
ungetc(ch,inf);
ch
是一个非字母字符,在下次调用
AdamRead
@ajay
ungetc(ch,inf)
时,如果在
AdamRead()之后调用另一个函数,它将被丢弃
将开始扫描非字母。@ajay也可能是字母。
ch
可能是字母。while循环可能由于
n
变为0而停止。OP的函数定义为o