c语言中从文件中按行读取字符串,并进行相应操作。
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c语言中从文件中按行读取字符串,并进行相应操作。相关的知识,希望对你有一定的参考价值。
举例:文件aa.txt 中有n行数据,格式是 字段一\t字段二\t字段三\t字段四\t\n
现在我已经将每行数据存放到arr[][]数组中,将(所有)数据字段存放到arr_b[][]数组中(arr_b【0】存放的是第一行第一个字段,arr_b【4】存放的是第二行第一个字段....),请问该如何根据字段一进行去重操作,根据字段三进行排序操作呢?
我要将处理后的数据写入到另一个文件中,去重,排序,保留原来格式。去重的意思是,去除重复行
#include "stdio.h"
#define ColNum 4 //总列数
#define QCIndex (1-1) //去重列号
#define PXIndex (3-1) //排序列号
typedef struct txtnode
struct txtnode* next;
char* col[ColNum];
TXTNODE;
void CopyToNode(TXTNODE*node,char *buf)
if(!buf||!*buf) return;
int j,len = strlen(buf);
char *p = (char*)malloc(len+1);
strcpy(p, buf);
node->col[0] = p;
for(j=1; *p&&j<ColNum; p++)
if(*p=='\t')
*p++='\0';
if(*p) node->col[j++] = p;
if(j<ColNum) node->col[0][0] = '\0';//放弃列数不足的行
int findnode(TXTNODE*Head,TXTNODE*node,int colIndex)
if(Head)
for(TXTNODE*p=Head; p; p=p->next)
if(strcmp(node->col[colIndex], p->col[colIndex])==0) return 1;
return 0;
int insertNode(TXTNODE**Head,TXTNODE*node,int colIndex)
TXTNODE*p0,*p1;
for(p0=NULL,p1=*Head; p1; p0=p1,p1=p1->next)
if(strcmp(node->col[colIndex], p1->col[colIndex])>=0)continue; //升序用>=0 降序排则用<=0
if(p0)//插在p0后p1前
p0->next=node;
node->next = p1;
else//插在开头
*Head = node;
node->next = p1;
return 0;
if(p0)//插在末尾 p1==NULL
p0->next=node;
node->next = NULL;
else//第一次调用 走到这里
*Head = node;
node->next = NULL;
return 0;
void deleteLink(TXTNODE**Head)
TXTNODE *p0,*p1;
p1 = *Head;
while(p1)
p0 = p1;
p1=p1->next;
free(p0->col[0]);
free(p0);
*Head = NULL;
void writeLink(TXTNODE*Head,FILE*wfp)
TXTNODE *p0=Head;
int i;
while(p0)
for(i=0; i<ColNum-1; i++)
fprintf(wfp,"%s\t",p0->col[i]);
fprintf(wfp,"%s",p0->col[i]);
p0=p0->next;
TXTNODE* readTxt(FILE*rfp)
char buf[10240]=0;
TXTNODE* head=NULL, *tmp;
while(!feof(rfp))
fgets(buf,10240,rfp);
if(!*buf) continue;
tmp=(TXTNODE*)malloc(sizeof(TXTNODE));
memset(tmp,0,sizeof(TXTNODE));
CopyToNode(tmp,buf);
if(tmp->col[0][0] && !findnode(head, tmp, QCIndex))
insertNode(&head, tmp, PXIndex);
else
free(tmp->col[0]);
free(tmp);
return head;
void main(int argc,char*argv[])
FILE *rfp,*wfp;
TXTNODE*Head = NULL;
if(argc<3)printf("去重排序小程序,调用格式:\n命令名 源文件 目标文件");exit(-1);
rfp = fopen(argv[1],"rb");
if(rfp==NULL)printf("源文件[%s]打不开",argv[1]);exit(-2);
wfp = fopen(argv[2],"wb");
if(wfp==NULL)fclose(rfp);printf("目标文件[%s]打不开",argv[2]);exit(-2);
Head = readTxt(rfp);
writeLink(Head,wfp);
fclose(rfp);
fclose(wfp);
deleteLink(&Head);
printf("处理完毕!\n");
//VC7下调试运行通过,功能正常 方便改造
//我闲得蛋痛了,花一两小时时间给你做这小程序(调试费了好一会才通过),没有分送,大大的不值 参考技术A #include
"stdafx.h"
#include
"stdio.h"
#define
ColNum
4
//总列数
#define
QCIndex
(1-1)
//去重列号
#define
PXIndex
(3-1)
//排序列号
typedef
struct
txtnode
struct
txtnode*
next;
char*
col[ColNum];
TXTNODE;
void
CopyToNode(TXTNODE*node,char
*buf)
if(!buf||!*buf)
return;
int
j,len
=
strlen(buf);
char
*p
=
(char*)malloc(len+1);
strcpy(p,
buf);
node->col[0]
=
p;
for(j=1;
*p&&j<ColNum;
p++)
if(*p=='\t')
*p++='\0';
if(*p)
node->col[j++]
=
p;
if(j<ColNum)
node->col[0][0]
=
'\0';//放弃列数不足的行
int
findnode(TXTNODE*Head,TXTNODE*node,int
colIndex)
if(Head)
for(TXTNODE*p=Head;
p;
p=p->next)
if(strcmp(node->col[colIndex],
p->col[colIndex])==0)
return
1;
return
0;
int
insertNode(TXTNODE**Head,TXTNODE*node,int
colIndex)
TXTNODE*p0,*p1;
for(p0=NULL,p1=*Head;
p1;
p0=p1,p1=p1->next)
if(strcmp(node->col[colIndex],
p1->col[colIndex])>=0)continue;
//升序用>=0
降序排则用<=0
if(p0)//插在p0后p1前
p0->next=node;
node->next
=
p1;
else//插在开头
*Head
=
node;
node->next
=
p1;
return
0;
if(p0)//插在末尾
p1==NULL
p0->next=node;
node->next
=
NULL;
else//第一次调用
走到这里
*Head
=
node;
node->next
=
NULL;
return
0;
void
deleteLink(TXTNODE**Head)
TXTNODE
*p0,*p1;
p1
=
*Head;
while(p1)
p0
=
p1;
p1=p1->next;
free(p0->col[0]);
free(p0);
*Head
=
NULL;
void
writeLink(TXTNODE*Head,FILE*wfp)
TXTNODE
*p0=Head;
int
i;
while(p0)
for(i=0;
i<ColNum-1;
i++)
fprintf(wfp,"%s\t",p0->col[i]);
fprintf(wfp,"%s",p0->col[i]);
p0=p0->next;
TXTNODE*
readTxt(FILE*rfp)
char
buf[10240]=0;
TXTNODE*
head=NULL,
*tmp;
while(!feof(rfp))
fgets(buf,10240,rfp);
if(!*buf)
continue;
tmp=(TXTNODE*)malloc(sizeof(TXTNODE));
memset(tmp,0,sizeof(TXTNODE));
CopyToNode(tmp,buf);
if(tmp->col[0][0]
&&
!findnode(head,
tmp,
QCIndex))
insertNode(&head,
tmp,
PXIndex);
else
free(tmp->col[0]);
free(tmp);
return
head;
void
main(int
argc,char*argv[])
FILE
*rfp,*wfp;
TXTNODE*Head
=
NULL;
if(argc<3)printf("去重排序小程序,调用格式:\n命令名
源文件
目标文件");exit(-1);
rfp
=
fopen(argv[1],"rb");
if(rfp==NULL)printf("源文件[%s]打不开",argv[1]);exit(-2);
wfp
=
fopen(argv[2],"wb");
if(wfp==NULL)fclose(rfp);printf("目标文件[%s]打不开",argv[2]);exit(-2);
Head
=
readTxt(rfp);
writeLink(Head,wfp);
fclose(rfp);
fclose(wfp);
deleteLink(&Head);
printf("处理完毕!\n");
//VC7下调试运行通过,功能正常
方便改造
//我闲得蛋痛了,花一两小时时间给你做这小程序(调试费了好一会才通过),没有分送,大大的不值 参考技术B 用fgets()就可以实现;
参考如下:
FILE *fp;
char str[256];
fgets(str, 256, fp);
意思为从fp中读一行,放入str中;
如果需要记录行号的话,设定个量计数就可以。 参考技术C 使用数组的话去重可以向后搜索,遇到空的跳过、重复的删除(变为空)。
但是排序很困难呢。
建议使用动态链表,这样去重,排序都非常方便追问
其实我早就想用的,由于是新手初学,哎。。后悔了,我现在用数组做的差不多了,再改就不大好了,其实用动态链表的话很简单的
参考技术D 去重:依次比较每两个数组,如果有重复的将其中一个做标记,表示是重复的,在最后需要写入另一文件中时,只要依次写入每条记录,碰到有标记的就不写入即可。注意标记应与所有数据不相同的。排序:对字段三进行排序,方法自选,简单的就是冒泡排序,只是每次比较字段三的数据,然后对换这一行信息内容,比如,如果按照自小到大顺序排,i<j,arr_b[i][2]>arr_b[j][2],就将arr_b[i]和arr_b[j]都对换就可以了。
使用 sed 提取文本文件以删除另一个文件中按行给出的后缀
【中文标题】使用 sed 提取文本文件以删除另一个文件中按行给出的后缀【英文标题】:Stemming a text file to remove suffixes given linewise in another file using sed 【发布时间】:2021-11-14 11:45:21 【问题描述】:我有一个文件suffix.txt
,其中包含一些按行排列的字符串,例如-
ing
ness
es
ed
tion
另外,我有一个文本文件text.txt
,其中包含一些文本,
假设text.txt
仅由小写字母组成,没有任何标点符号,例如-
the raining cloud answered the man all his interrogation and with all
questioned mind the princess responded
harness all goodness without getting irritated
我只想为每个后缀从text.txt
中的原始单词中删除后缀一次。因此,我期望以下输出-
the rain cloud answer the man all his interroga and with all
question mind the princess respond
har all good without gett irritat
请注意,tion
并未从 questioned
中删除,因为原始单词不包含 tion
作为后缀。如果有人可以用sed
命令回答这个问题,那将非常有帮助。
我正在使用一个似乎无法完成工作的天真的脚本-
#!/bin/bash
while read p; do
sed -i "s/$p / /g" text.txt;
sed -i "s/$p$//g" text.txt;
done <suffix.txt
【问题讨论】:
【参考方案1】:有点麻烦,但仅限 sed 和 unix 工具:
sed -E -f <(tr '\n' '|' <suffix.txt | sed 's/\|$//; s/\|/\\\\b|/g; s/$/\\\\b/' | xargs printf 's/%s//g') text.txt
tr '\n' '|' <suffix.txt | sed 's/\|$//; s/\|/\\\\b|/g; s/$/\\\\b/' | xargs printf 's/%s//g'
生成替换脚本
s/ing\b|ness\b|es\b|ed\b|tion\b//g
这需要 GNU sed for \b
。
使用 perl、ruby、awk 等会更容易
这是一个 GNU awk:
gawk -i join 'FNR==NR arr[FNR]=$1; next
FNR==1re=join(arr,1,length(arr),"\\>|"); re=re "\\>"
gsub(re,"")
1
' suffix.txt text.txt
两者都产生:
the rain cloud answer the man all his interroga and with all
question mind the princess respond
har all good without gett irritat
【讨论】:
实际上这并没有提供所需的输出。 您可能没有使用 GNU sed。【参考方案2】:你可以试试这个sed
方法。
您首先需要从suffix.txt
创建一个数组
suffix=($(cat suffix.txt))
然后您可以在主 sed
代码中使用它进行替换。
sed " s/$suffix[0]//;s/$suffix[1]//g;/question/! s/$suffix[2]//;s/$suffix[3]//g;/question/! s/$suffix[4]//" text.txt
输出
the rain cloud answer the man all his interroga and with all
question mind the princess respond
har all good without gett irritat
【讨论】:
对不起,这至少对我来说似乎不对,对于这个例子,它似乎是硬编码的,而且你在哪里确保 suffix.txt 中的字符串(即后缀数组)实际上是在这个词的结尾?【参考方案3】:一个 awk:
$ awk '
NR==FNR # generate a regex of suffices
s=s (s==""?"(":"|") $0 # (ing|ness|es|ed|tion)$
next
FNR==1
s=s ")$" # well, above )$ is inserted here
for(i=1;i<=NF;i++) # iterate all the words and
sub(s,"",$i) # apply regex to each of them
1' suffix text # output
输出:
the rain cloud answer the man all his interroga and with all
question mind the princess respond
har all good without gett irritat
【讨论】:
【参考方案4】:这可能对你有用(GNU sed):
sed -z 'y/\n/|/;s/|$//;s#.*#s/\\B(&)\\b//g#' suffixFile | sed -Ef - textFile
将 suffixFile 转换为文件中的 sed 命令,并通过管道将其传递给修改 textFile 的第二次 sed 调用。
注意sed 命令使用\B
和\b
来匹配后缀。
【讨论】:
谢谢,它成功了,但是你能解释一下你的代码吗?以上是关于c语言中从文件中按行读取字符串,并进行相应操作。的主要内容,如果未能解决你的问题,请参考以下文章