我有两个文件file1.txt
,file2.txt
,我想在检查两个文件的行后在file3.txt
收集它们。
示例:
FILE1.TXT
line 1 T
line 2 F
line 3 T
line 4 T
line 5 F
line 6 F
FILE2.TXT
line 1 T
line 2 T
line 3 F
line 4 T
line 5 F
line 6 T
file3.txt
file1
********************
number of line = 6
number of true = 3
number of false = 3
********************
line 1 T
line 3 T
line 4 T
file2
********************
number of line = 6
number of true = 4
number of false = 2
********************
line 1 T
line 2 T
line 4 T
line 6 T
对于每个文件,生成的文件应包含一个标题,显示行数,真实行数(T
)和假行数(F
)。接下来仅打印真实的行。
一些帮助?
答案 0 :(得分:2)
这是一个粗略的草图,可以帮助您开始使用swi-prolog和library(pio)
。
我们将lines//1
定义为我{@ 3}}中的@mat到相关问题“his answer”。然后使用Read a file line by line in Prolog和tpartition/4
编写:
?- prefix_of_t/3
(set_prolog_flag , codes),
set_prolog_flag(toplevel_print_anon, false).
true.
?- double_quotes(phrase_from_file(_Ls), 'file1.txt'),
lines(maplist, _Ls, _Rs),
reverse(tpartition("T"), _Rs, _Ts0, _Fs),
maplist(reverse, _Ts0, _Ts),
prefix_of_t(forall(X,_Ts), member('~s~n',[X])).
line 1 T
line 3 T
line 4 T
true.
答案 1 :(得分:1)
您可以按照以下方式执行此操作。我们首先定义谓词merge/2
,第一项是必须读取的文件名列表(此处为[file1.txt,file2.txt]
),第二项参数是您要写入的文件名(此处为{{ 1}})。现在我们将file3.txt
定义为:
merge/2
因此,我们打开一个名为merge(Inp,Outp) :-
open(Outp,write,Outs),
mergeS(Inp,Outs).
的文件并获取相应的流Outp
,然后调用Outs
。
mergeS/2
有两种情况:
所有输入文件都已处理完毕,因此我们可以停止处理并关闭流:
mergeS/2
我们还需要处理至少一个文件:
mergeS([],OutS) :-
close(OutS).
这个谓词的核心显然是mergeS([H|T],OutS) :-
open(H,read,InS),
atom_chars(FileN,H),
process(FileN,InS,OutS),
close(InS),
mergeS(T,OutS).
,但为了使事情更方便。我们已在process/3
。
接下来,我们的 mergeS
谓词为:
process/3
我们首先使用process(Header,InS,OutS) :-
get_lines(InS,Lin,NL,NT,NF),
write(OutS,Header),nl(OutS),
write(OutS,'********************'),nl(OutS),
write(OutS,'number of line = '),write(OutS,NL),nl(OutS),
write(OutS,'number of true = '),write(OutS,NT),nl(OutS),
write(OutS,'number of false = '),write(OutS,NF),nl(OutS),
write(OutS,'********************'),nl(OutS),
print_lines(OutS,Lin),
nl(OutS).
收集文件的内容。该谓词将同时计算统计数据,如行数,真实数和假数。接下来,我们使用许多get_lines/5
和write/2
语句将统计信息写入输出文件,然后使用谓词nl/1
将谓词文件的内容写入print_lines/2
:
file3.txt
和get_lines
get_line
使用三个累加器来计算统计数据。这是通过初始化三个累加器然后调用get_lines/5
来完成的:
get_lines/8
get_lines(Ins,Lin,NL,NT,NF) :-
get_lines(Ins,Lin,0,0,0,NL,NT,NF).
是一个递归函数,一次处理一行,确定该行是get_lines/8
还是T
,更新累加器,并解析下一行。但是我们可能会得到一个空文件。为了使我们的方法更加健壮,我们写道:
F
和递归案例:
get_lines(InS,[],NL,NT,NF,NL,NT,NF) :-
at_end_of_stream(InS),
!.
get_lines(InS,[H|T],NL0,NT0,NF0,NL,NT,NF) :-
get_line(InS,HCs),
inspect(HCs,NL0,NT0,NF0,NL1,NT1,NF1),
atom_chars(H,HCs),
get_lines(InS,T,NL1,NT1,NF1,NL,NT,NF).
只是读取文件的下一行,并返回一个字符流。它终止于get_line/2
(包括但不在结果中)。
'\n'
<强> get_line(InS,[]) :-
at_end_of_stream(InS),
!.
get_line(InS,[H|T]) :-
get_char(InS,H),
H \= '\n',
!,
get_line(InS,T).
get_line(_,[]).
强>
现在我们仍然需要使用inspect/7
检查我们的行。我们再次使用三个累加器(正如您已经根据inspect/7
的实现而猜测的那样)。首先,我们获取该行的最后一个字符。如果不存在这样的字符,则统计信息不会更改(可能会在某处引入空行)。否则,我们会使用get_lines/8
获取最后一个字符,并使用last/2
进行检查:
inspect_last/7
inspect(L,NL0,NT0,NF0,NL,NT,NF) :-
last(L,LL),
!,
NL is NL0+1,
inspect_last(LL,NT0,NF0,NT,NF).
inspect(_,NL0,NT,NF,NL1,NT,NF) :-
!,
NL1 is NL0+1.
确定最后一个字符是inspect_last
,T
还是其他字符,并相应地更新累加器:
F
<强> inspect_last('T',NT0,NF,NT1,NF) :-
!,
NT1 is NT0+1.
inspect_last('F',NT,NF0,NT,NF1) :-
!,
NF1 is NF0+1.
inspect_last(_,NT,NF,NT,NF).
强>:
最后我们仍然需要将文件打印到输出。这是使用print_lines/2
完成的,这很简单:
print_lines/2
完整代码:
print_lines(_,[]) :-
!.
print_lines(OutS,[H|T]) :-
write(OutS,H),
nl(OutS),
print_lines(OutS,T).
如果现在查询:
merge(Inp,Outp) :-
open(Outp,write,Outs),
mergeS(Inp,Outs).
mergeS([],OutS) :-
close(OutS).
mergeS([H|T],OutS) :-
open(H,read,InS),
atom_chars(FileN,H),
process(FileN,InS,OutS),
close(InS),
mergeS(T,OutS).
process(Header,InS,OutS) :-
get_lines(InS,Lin,NL,NT,NF),
write(OutS,Header),nl(OutS),
write(OutS,'********************'),nl(OutS),
write(OutS,'number of line = '),write(OutS,NL),nl(OutS),
write(OutS,'number of true = '),write(OutS,NT),nl(OutS),
write(OutS,'number of false = '),write(OutS,NF),nl(OutS),
write(OutS,'********************'),nl(OutS),
print_lines(OutS,Lin),
nl(OutS).
get_lines(Ins,Lin,NL,NT,NF) :-
get_lines(Ins,Lin,0,0,0,NL,NT,NF).
get_lines(InS,[],NL,NT,NF,NL,NT,NF) :-
at_end_of_stream(InS),
!.
get_lines(InS,[H|T],NL0,NT0,NF0,NL,NT,NF) :-
get_line(InS,HCs),
inspect(HCs,NL0,NT0,NF0,NL1,NT1,NF1),
atom_chars(H,HCs),
get_lines(InS,T,NL1,NT1,NF1,NL,NT,NF).
get_line(InS,[]) :-
at_end_of_stream(InS),
!.
get_line(InS,[H|T]) :-
get_char(InS,H),
H \= '\n',
!,
get_line(InS,T).
get_line(_,[]).
inspect(L,NL0,NT0,NF0,NL,NT,NF) :-
last(L,LL),
!,
NL is NL0+1,
inspect_last(LL,NT0,NF0,NT,NF).
inspect(_,NL0,NT,NF,NL1,NT,NF) :-
!,
NL1 is NL0+1.
inspect_last('T',NT0,NF,NT1,NF) :-
!,
NT1 is NT0+1.
inspect_last('F',NT,NF0,NT,NF1) :-
!,
NF1 is NF0+1.
inspect_last(_,NT,NF,NT,NF).
print_lines(_,[]) :-
!.
print_lines(OutS,[H|T]) :-
write(OutS,H),
nl(OutS),
print_lines(OutS,T).
名为?- merge(["file1.txt","file2.txt"],"file3.txt").
true.
的文件由内容构建:
file3.txt
这或多或少是你想要的。如果发生进一步的错误,请评论。
修改强>
不知何故,我没有让你想要过滤行,只显示真实的行(file1.txt
********************
number of line = 6
number of true = 3
number of false = 3
********************
line 1 T
line 2 F
line 3 T
line 4 T
line 5 F
line 6 F
file2.txt
********************
number of line = 6
number of true = 4
number of false = 2
********************
line 1 T
line 2 T
line 3 F
line 4 T
line 5 F
line 6 T
)。您只需修改T
:
get_lines(InS,[],NL,NT,NF,NL,NT,NF) :- at_end_of_stream(InS), !. get_lines(InS,Res,NL0,NT0,NF0,NL,NT,NF) :- get_line(InS,HCs), inspect(HCs,NL0,NT0,NF0,NL1,NT1,NF1), atom_chars(H,HCs), ( NT1 > NT0 -> Res =[H|T] ; Res = T ), get_lines(InS,T,NL1,NT1,NF1,NL,NT,NF).
(在内容改变的地方添加了粗体字)
这不是最优雅的方式,但它可能是最短的修复方法。
现在我机器上的文件显示:
get_lines/7