Prolog 为文件输入创建dcg的一般模式是什么?

Prolog 为文件输入创建dcg的一般模式是什么?,prolog,swi-prolog,dcg,fasta,Prolog,Swi Prolog,Dcg,Fasta,我似乎总是很难编写DCG来解析输入文件。但它似乎应该很简单?关于这个问题有什么建议或技巧吗 举个具体的例子,假设我想解析一个fasta文件。(). 我想阅读回溯中的每个描述和序列 :- use_module(library(pio)). :- use_module(library(dcg/basics)). :- portray_text(true). :- set_prolog_flag(double_quotes, codes). :- set_prolog_flag(back_quotes

我似乎总是很难编写DCG来解析输入文件。但它似乎应该很简单?关于这个问题有什么建议或技巧吗

举个具体的例子,假设我想解析一个fasta文件。(). 我想阅读回溯中的每个描述和序列

:- 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.

但是如果我使用了
短语(fasta_文件(节),“>frog\nACGGGGTACG\n>duck\nACGTTAG)。
节与节列表相统一/2,这是我想要的,但我当前的代码似乎相当粗糙-例如,我是如何处理换行符的。

当然,有一些“小”的键入问题:

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(?)奇怪的编码时,我感到很痛苦

我建议使用短语/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".
现在

注意:子句fasta_seq//1的顺序很重要,因为它实现了一个“急切”的解析——主要是为了提高效率。正如我所说,我必须解析SQL,几个MBs是常见的

编辑


fasta_section//1意味着匹配一个确定的序列。要获得所有回溯,我们必须提供一个回溯点。在这种情况下,字符串//1来自库(dcg/BASIC)工作是否很抱歉,逗号是问题中的一个输入错误。我现在对这些内容使用双引号,对字符串使用反引号,因为这似乎是最兼容的方式。如果我想使用fasta_section//1和back track来找到每个解决方案,该怎么办?输入错误:
S=“X”->
应该是
[S]=“X”“->
将引起您的兴趣。将
{Section=…[Section,Description,Sequence]}
替换为
{Section=Section(Description,Sequence)}
?- phrase(fasta_file(S), `>frog\nACGGGGTACG\n>duck\nACGTTAG`).
S = [section(frog, 'ACGGGGTACG'), section(duck, 'ACGTTAG')] ;
false.
?- phrase((string(_),fasta_section(S)), `>frog\nACGGGGTACG\n>duck\nACGTTAG`,_).
S = section(frog, 'ACGGGGTACG') ;
S = section(duck, 'ACGTTAG') ;
false.