为文件输入创建 dcg 的一般模式是什么?
What is the general pattern for creating a dcg for file input?
我似乎总是在努力编写 DCG 来解析输入文件。不过好像应该很简单吧?有什么提示或技巧可以考虑这个问题吗?
举个具体的例子,假设我想解析一个fasta文件。 (https://en.wikipedia.org/wiki/FASTA_format)。我想阅读每个描述和每个序列的回溯。
:- use_module(library(pio)).
:- use_module(library(dcg/basics)).
:- portray_text(true).
:- set_prolog_flag(double_quotes, codes).
:- set_prolog_flag(back_quotes,string).
fasta_file([]) -->[].
fasta_file([Section|Sections]) -->
fasta_section(Section),
fasta_file(Sections).
fasta_section(Section) -->
fasta_description(Description),
fasta_seq(Sequence),
{Section =.. [section,Description,Sequence]}.
fasta_description(Description) -->
">",
string(Description),
{no_gt(Description),
no_nl(Description)}.
fasta_seq([]) --> [].
fasta_seq(Seq) -->
nt([S]),
fasta_seq(Ss),
{S="X"->Seq =Ss;Seq=[S|Ss]}.
nt("A") --> "A".
nt("C") --> "C".
nt("G") --> "G".
nt("T") --> "T".
nt("X") --> "\n".
no_gt([]).
no_gt([E|Es]):-
dif([E],">"),
no_gt(Es).
no_nl([]).
no_nl([E|Es]):-
dif([E],"\n"),
no_nl(Es).
这显然是错误的。我想要的行为是
?-phrase(fasta_section(S),">frog\nACGGGGTACG\n>duck\nACGTTAG").
S = section("frog","ACGGGGTACG");
S = section("duck","ACGTTAG");
false.
但如果我这样做了 phrase(fasta_file(Sections),">frog\nACGGGGTACG\n>duck\nACGTTAG).
部分与 sections/2s 的列表统一,这就是我想要的,但我当前的代码似乎很老套 - 例如我如何处理换行符.
肯定有 'small' 个打字问题:
nt("A") -->"A",
nt("C") -->"C",
nt("G") -->"G",
nt("T") -->"T".
应该是
nt("A") -->"A".
nt("C") -->"C".
nt("G") -->"G".
nt("T") -->"T".
无论如何,我在调试 DCG 时也遇到了问题,我编写了一个解析器来在 Prolog 中加载一个 MySQL 转储(普通的 SQL,真的),并且在出现意外情况时很痛苦,比如发现了转义字符串或 UTF8 (?) 奇怪的编码。
我建议使用phrase/3,看看是否有无法解析的尾巴。此外,可以帮助在已知的、行为良好的序列之后放置一些调试输出。
当然,我假设您已经尝试使用 SWI-Prolog 调试器。
另外,提防
...
dif([E],">"),
...
您是否设置了有关双引号的适当标志?在 DCG 主体中,重写机制负责匹配,但默认情况下 SWI-Prolog 中的一系列代码 不会 匹配双引号字符串...
编辑
我认为这不会解决您对一般策略的疑问...无论如何,这就是我处理问题的方式...
fasta_file([]) -->[].
fasta_file([Section|Sections]) -->
fasta_section(Section),
fasta_file(Sections).
fasta_section(section(Description,Sequence)) -->
fasta_description(Description),
fasta_seq(SequenceCs), {atom_codes(Sequence, SequenceCs)}, !.
fasta_description(Description) -->
">", string(DescriptionCs), "\n", {atom_codes(Description, DescriptionCs)}.
fasta_seq([S|Seq]) --> nt(S), fasta_seq(Seq).
fasta_seq([]) --> "\n" ; []. % optional \n at EOF
nt(0'A) --> "A".
nt(0'C) --> "C".
nt(0'G) --> "G".
nt(0'T) --> "T".
现在
?- phrase(fasta_file(S), `>frog\nACGGGGTACG\n>duck\nACGTTAG`).
S = [section(frog, 'ACGGGGTACG'), section(duck, 'ACGTTAG')] ;
false.
注意:子句 fasta_seq//1 的顺序很重要,因为它实现了 'eager' 解析 - 主要是为了提高效率。正如我所说,我不得不解析 SQL,几个 MB 是常见的。
编辑
?- phrase((string(_),fasta_section(S)), `>frog\nACGGGGTACG\n>duck\nACGTTAG`,_).
S = section(frog, 'ACGGGGTACG') ;
S = section(duck, 'ACGTTAG') ;
false.
fasta_section//1表示匹配一个确定的序列。为了得到所有的回溯,我们必须提供一个回溯点。在这种情况下,库中的 string//1(dcg/basics) 完成工作
我似乎总是在努力编写 DCG 来解析输入文件。不过好像应该很简单吧?有什么提示或技巧可以考虑这个问题吗?
举个具体的例子,假设我想解析一个fasta文件。 (https://en.wikipedia.org/wiki/FASTA_format)。我想阅读每个描述和每个序列的回溯。
:- use_module(library(pio)).
:- use_module(library(dcg/basics)).
:- portray_text(true).
:- set_prolog_flag(double_quotes, codes).
:- set_prolog_flag(back_quotes,string).
fasta_file([]) -->[].
fasta_file([Section|Sections]) -->
fasta_section(Section),
fasta_file(Sections).
fasta_section(Section) -->
fasta_description(Description),
fasta_seq(Sequence),
{Section =.. [section,Description,Sequence]}.
fasta_description(Description) -->
">",
string(Description),
{no_gt(Description),
no_nl(Description)}.
fasta_seq([]) --> [].
fasta_seq(Seq) -->
nt([S]),
fasta_seq(Ss),
{S="X"->Seq =Ss;Seq=[S|Ss]}.
nt("A") --> "A".
nt("C") --> "C".
nt("G") --> "G".
nt("T") --> "T".
nt("X") --> "\n".
no_gt([]).
no_gt([E|Es]):-
dif([E],">"),
no_gt(Es).
no_nl([]).
no_nl([E|Es]):-
dif([E],"\n"),
no_nl(Es).
这显然是错误的。我想要的行为是
?-phrase(fasta_section(S),">frog\nACGGGGTACG\n>duck\nACGTTAG").
S = section("frog","ACGGGGTACG");
S = section("duck","ACGTTAG");
false.
但如果我这样做了 phrase(fasta_file(Sections),">frog\nACGGGGTACG\n>duck\nACGTTAG).
部分与 sections/2s 的列表统一,这就是我想要的,但我当前的代码似乎很老套 - 例如我如何处理换行符.
肯定有 'small' 个打字问题:
nt("A") -->"A",
nt("C") -->"C",
nt("G") -->"G",
nt("T") -->"T".
应该是
nt("A") -->"A".
nt("C") -->"C".
nt("G") -->"G".
nt("T") -->"T".
无论如何,我在调试 DCG 时也遇到了问题,我编写了一个解析器来在 Prolog 中加载一个 MySQL 转储(普通的 SQL,真的),并且在出现意外情况时很痛苦,比如发现了转义字符串或 UTF8 (?) 奇怪的编码。
我建议使用phrase/3,看看是否有无法解析的尾巴。此外,可以帮助在已知的、行为良好的序列之后放置一些调试输出。
当然,我假设您已经尝试使用 SWI-Prolog 调试器。
另外,提防
...
dif([E],">"),
...
您是否设置了有关双引号的适当标志?在 DCG 主体中,重写机制负责匹配,但默认情况下 SWI-Prolog 中的一系列代码 不会 匹配双引号字符串...
编辑
我认为这不会解决您对一般策略的疑问...无论如何,这就是我处理问题的方式...
fasta_file([]) -->[].
fasta_file([Section|Sections]) -->
fasta_section(Section),
fasta_file(Sections).
fasta_section(section(Description,Sequence)) -->
fasta_description(Description),
fasta_seq(SequenceCs), {atom_codes(Sequence, SequenceCs)}, !.
fasta_description(Description) -->
">", string(DescriptionCs), "\n", {atom_codes(Description, DescriptionCs)}.
fasta_seq([S|Seq]) --> nt(S), fasta_seq(Seq).
fasta_seq([]) --> "\n" ; []. % optional \n at EOF
nt(0'A) --> "A".
nt(0'C) --> "C".
nt(0'G) --> "G".
nt(0'T) --> "T".
现在
?- phrase(fasta_file(S), `>frog\nACGGGGTACG\n>duck\nACGTTAG`).
S = [section(frog, 'ACGGGGTACG'), section(duck, 'ACGTTAG')] ;
false.
注意:子句 fasta_seq//1 的顺序很重要,因为它实现了 'eager' 解析 - 主要是为了提高效率。正如我所说,我不得不解析 SQL,几个 MB 是常见的。
编辑
?- phrase((string(_),fasta_section(S)), `>frog\nACGGGGTACG\n>duck\nACGTTAG`,_).
S = section(frog, 'ACGGGGTACG') ;
S = section(duck, 'ACGTTAG') ;
false.
fasta_section//1表示匹配一个确定的序列。为了得到所有的回溯,我们必须提供一个回溯点。在这种情况下,库中的 string//1(dcg/basics) 完成工作