2016-03-27 3 views
2

привет, я пытался создать код, который мог бы найти данный символ из входного файла и распечатать его позицию, вот что я вышел с помощью «с помощью подобных проблем, которые я нашел»,Поиск в файлах в прологе

process2(Text,POS):- 
    open('houses.txt', read, In), 
    get_char(In, Char1), 
    find(Char1, In,Text,POS), 
    close(In). 

find(Text,In, Text, 0). 
find(Char,In,Text,POS) :- 
    POS is POS1 +1, 
    get_char(In, Char2), 
    find(Char2,In,Text,POS1). 

однако компилятор выдает эту ошибку: оШИБКА: есть/2: аргументы не достаточно инстанцирован

+0

Операция 'is/2' требует, чтобы все переменные, которые вы вычисляете справа, были созданы. В этом случае 'POS1' не имеет значения, поэтому Prolog не может вычислить' POS1 + 1'. – lurker

+0

Я просто переместил это утверждение на последнее, и он сработал: POS - POS1 +1 спасибо alot <3 любая идея, как использовать, чтобы функция взяла подстроку вместо 1 символа tho? –

+0

Прежде чем что-либо предпринять: удалите предупреждения, которые вы определенно получаете! – false

ответ

2

при обработке ввода, всегда считают DCG первым:

 
:- use_module(library(pio)). 

process3(File, Text, POS) :- phrase_from_file(find(Text, POS), File). 

find(Text, [P|Ps]) --> 
    lazy_list_character_count (P), Text, !, 
    find(Text, Ps). 
find(Text, Ps) --> [_], find(Text, Ps). 
find(_Text, []) --> []. 

Это находит все позиции входной строки:

?- process3('/home/carlo/.swiplrc', `file`, P). 
P = [51, 174, 254, 452, 549, 1977, 2106, 3682, 4033|...] ; 
false. 

редактировать как предложил Борис, покрой может удалить некоторые законные решения. Итак, вот вырезанная бесплатная версия.

find(_Text, []) --> []. 
find(Text, [P|Ps]) --> 
    lazy_list_character_count(P), Text, 
    find(Text, Ps). 
find(Text, Ps) --> \+Text, [_], find(Text, Ps). 
+2

С помощью ['pio'] (http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/swi/pio.pl) вы также можете использовать символы. – false

+0

Я уверен, что разрез не позволит вам частично накладывать наложения «Текста»? –

+0

@Boris: Да, вы правы. Должна работать лучше. Я добавил его во время отладки ... проверит и удалит его.Спасибо – CapelliC

1

Это работает точно так же, как и ожидалось, если вы просто используете CLP (FD) ограничения вместо низкоуровневого арифметики:

:- use_module(library(clpfd)). 

find(Text, In, Text, 0). 
find(Char, In, Text, POS) :- 
     POS #= POS1 + 1, 
     get_char(In, Char2), 
     find(Char2,In,Text, POS1). 

Преимущество (FD) версии CLP, что это хвостовая рекурсия , что также вы интуитивно делали.

Я также рекомендую setup_call_cleanup/3, и даже лучше, library(pio) при обработке файлов. (Примечание:! В SICStus Прологе, вы можете установить флаг Пролог double_quotes в chars, а затем использовать DCGs для обработки файла в качестве символов Если вы заинтересованы в этом, лобби для поддержки в SWI)

Я оставляю это, и исправление оставшихся (завершающих) проблем в коде, в качестве упражнений.

+1

Я не знаю, как я отношусь к пощечине CLPFD над сомнительным подходом. Это делает его как-то одновременно лучше и более сомнительным. –

+1

Я чувствую себя точно так же. Я опубликовал это только для рассмотрения вопроса prima facie («аргументы недостаточно инстанцированы») OP, который к настоящему времени появился достаточно часто и который я хочу уменьшить. Мой опыт показал мне, что люди вряд ли будут принимать слишком много изменений сразу. Я надеюсь, что даже если они не будут полностью меняться на чистый код сразу, они, по крайней мере, немного улучшат свою ситуацию *, приняв CLP (FD). Каждое улучшение лучше, чем ничего. Тем не менее, я включаю указатели на лучшие способы и поддерживаю более чистые версии, которые я очень рекомендую. – mat

+0

Почему бы не решить проблему стойкости (в этом случае без побочных эффектов это будет вопрос монотонности)? – false

1

Один очень чистый способ сделать это - использовать DCG, например the answer from CapelliC. Как и он, используя изящную library(pio) Ульриха Neumerkel, например as found in SWI-Prolog, вы могли бы объединить DCG и phrase_from_file/2 для следующего решения:

:- use_module(library(pio)). 

... --> []|[_], ... . 

file_pattern_pos(File, Pattern, Pos) :- 
    phrase_from_file((..., 
         lazy_list_character_count(Pos), 
         Pattern, 
         ... 
        ), 
        File). 

Это взято дословно из примера кода в documentation to phrase_from_file/2, просто добавил lazy_list_character_count//1. В отличие от другого ответа DCG, он генерирует все решения при обратном отслеживании. Так с этим файлом:

$ cat banana.txt 
banana 
Antananarivo 

вы получаете от верхнего уровня:

?- file_pattern_pos("banana.txt", "ana", Pos). 
Pos = 1 ; 
Pos = 3 ; 
Pos = 10 ; 
Pos = 12 ; 
false. 

Чтобы составить список всех позиций одного символа:

?- bagof(P, file_pattern_pos("banana.txt", "a", P), Ps). 
Ps = [1, 3, 5, 10, 12, 14]. 

Это решение хорошо , потому что к нему легко добраться, просто просмотрев пример кода из документации до phrase_from_file/2.Однако в приведенных ниже замечаниях были указаны две проблемы:

  1. Вопрос об эффективности;
  2. Использование lazy_list_character_count//1 означает, что вы не можете использовать это с помощью phrase/2.

Вопрос эффективности может быть решена, как указано в комментарии:

... --> []. 
... --> [_], ... . 

Другой проблемой является более серьезным. В конце концов, возможно, необходимо подсчитать количество потребляемых символов. Например:

span(N) --> span_(0, N). 

span_(N, N) --> []. 
span_(N0, N) --> [_], 
    { N1 is N0 + 1 
    }, 
    span_(N1, N). 

Теперь мы можем написать, с верхнего уровня:

?- phrase_from_file((span(Pos), "ana", ...), "banana.txt"). 
Pos = 1 ; 
Pos = 3 ; 
Pos = 10 ; 
Pos = 12 ; 
false. 

Или, используя phrase/2:

?- phrase((span(P), "ana", ...), "banana"). 
P = 1 ; 
P = 3 ; 
false. 
+0

@repeat Мое решение предназначалось только для того, чтобы показать, как это сделать с помощью 'sub_atom/5' или' sub_string/5'; однако я чувствовал, что ответ на библиотеку (pio) был субоптимальным (я дал ему s (X) в любом случае, с риском быть нераскрытым), поэтому я добавил это к моему ответу. –

+0

@repeat dif (оскорбительный, оскорбительный) посмотрите его –

+2

@repeat Я точно знаю, как обычная голосующая/отвечающая толпа реакция на такой ответ. Я никогда не делал этого для воображаемых интернет-точек, поэтому мне действительно все равно. Но внимательно посмотрите: «чистое» решение сверху; решение с использованием строк и SWI-Prolog поставляется с честным предупреждением и предлагает использовать 'sub_atom/5', если проблема переносимости является проблемой. Просто говорю. –

0

Если вы намерены с помощью SWI-Пролог, вы можете использовать strings для работы с текстом в более простых случаях. В этом случае, например, достаточно, чтобы прочитать файл из потока In (как у вас есть в вашем вопросе) с помощью read_string/3 и найти позиции всех вхождений подстроки в нем с помощью sub_string/5:

setup_call_cleanup(open(File, read, In), 
        read_string(In, _, File_contents), 
        close(In)), 
sub_string(File_contents, Pos, _Length, _After, Substr) 

Вот и все. Pos будет 0-основанием позиции Substr. Для поиска символов, просто использовать строку длину 1. Одна из лучших вещей о sub_string/5 является то, что он правильно занимается частично перекрывающимися подстроками:

?- sub_string("banana", Pos, _, _, "ana"). 
Pos = 1 ; 
Pos = 3 ; 
false. 

Чем больше стандартным аналогом sub_string/5 является sub_atom/5 с идентичной семантикой как sub_string/5 , но беря атомы. Он должен быть доступен в каждой реализации Prolog.

?- sub_atom(banana, Pos, _, _, ana). 
Pos = 1 ; 
Pos = 3 ; 
false. 

После прочтения всего файла в кодах, просто использовать atom_codes/2 и затем sub_atom/5. Это, однако, несколько расточительно.

Как только вам нужно сделать более сложные вещи с содержимым файла, вы можете перейти к использованию DCG, library(pio) и т. Д. Возвращаясь к использованию примитивов чтения, так как get_char, как правило, не нужно. Тем не менее, я по-прежнему настоятельно рекомендую прочитать раздел руководства по строкам, приведенным выше.

+0

Что такое накладные расходы, используя:' read_atom (S, A): - read_string (S, _, Str), atom_string (A, Str) .' вместо? Я не могу измерить разницу. – false

+0

@false Существует едва ли разница. Как вы хорошо знаете, причина в том, что «строка», реализованная в SWI-Prolog, очень эффективна в пространстве и времени (читай «реализовать в C»), а преобразование из строки в атом возможно просто означает получение хэша C-строку, чтобы он мог быть проиндексирован движком (атомы должны быть идентификаторами, а не держателями для текста). Конечно, Ян Вилемейкер знает больше, чем я о деталях. Подводя итог, из-за реализации строк, очень мало накладных расходов при превращении одной струны в атом. –

+0

По-разному: нет причин иметь строки (как видимый тип данных), когда атомы предлагают именно эту функциональность. – false