Каков общий шаблон для создания dcg для ввода файла?

Кажется, мне всегда трудно писать 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). Разделы объединены списком разделов /2, и это то, что я хочу, но мой текущий код кажется довольно хакерским - как, например, я обработал символ новой строки.

1 ответ

Решение

Наверняка, есть "небольшие" проблемы с печатанием:

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

сейчас

?- phrase(fasta_file(S), `>frog\nACGGGGTACG\n>duck\nACGTTAG`).
S = [section(frog, 'ACGGGGTACG'), section(duck, 'ACGTTAG')] ;
false.

примечание: порядок предложений fasta_seq//1 важен, так как он реализует "нетерпеливый" анализ - в основном для эффективности. Как я уже говорил, мне пришлось разбирать SQL, несколько мегабайт было обычным.

редактировать

?- phrase((string(_),fasta_section(S)), `>frog\nACGGGGTACG\n>duck\nACGTTAG`,_).
S = section(frog, 'ACGGGGTACG') ;
S = section(duck, 'ACGTTAG') ;
false.

fasta_section//1 означает совпадение с определенной последовательностью. Чтобы все вернуть назад, мы должны предоставить точку возврата. В этом случае строка // 1 из библиотеки (dcg/basics) выполняет свою работу

Другие вопросы по тегам