Сибирский университет потребительской кооперации
Опубликован: 04.05.2005 | Доступ: свободный | Студентов: 4322 / 1347 | Оценка: 4.45 / 4.22 | Длительность: 12:28:00
ISBN: 978-5-9556-0034-5
Лекция 11:

Строки

< Лекция 10 || Лекция 11: 1234 || Лекция 12 >

Пример. Теперь попробуем немного модифицировать описанный предикат так, чтобы он преобразовывал строку не в список символов, а в список атомов.

Отличаться предыдущее решение будет заменой предиката frontchar на предикат fronttoken. Да еще надо не забыть в разделе описания предикатов заменить домен второго параметра со списка символов на список строк.

Запишем эту идею:

str_a_list("",[]). /* пустой строке по-прежнему 
                 соответствует пустой список */
str_a_list(S,[H|T]):–
              fronttoken(S,H,S1), 
                    /* H — первый атом строки S, 
                       S1 — остаток строки */
              str_a_list(S1,T). 
                      /* T — список, состоящий 
                        из атомов, входящих 
                        в строку S1*/

Кстати, этот же предикат можно задействовать для создания списка слов, входящих в строку. Если слова разделены только пробелами, то он подойдет безо всяких изменений. Если же в строку могут входить еще и знаки препинания, то каждый из них попадет в итоговый список отдельным элементом. Для того чтобы получить список, элементами которого являются только слова, можно просто удалить из него все знаки препинания, что не сложно. К сожалению, работать эта идея будет только на английских словах. Русский текст этот предикат разобьет на отдельные символы, а не на слова.

Пример. Разработаем предикат, который будет преобразовывать список символов в строку. Предикат будет иметь два аргумента. Первым аргументом будет список символов, вторым — строка, образованная из элементов списка.

Базис рекурсии: пустому списку соответствует пустая строка. Шаг: если исходный список не пуст, то нужно перевести в строку его хвост, после чего, используя стандартный предикат frontchar, приписывать к первому элементу списка строку, полученную из хвоста исходного списка.

Запишем эту идею:

list_str([],""). /* пустой строке соответствует 
                пустой список */
list_str([H|T],S):–
            list_str(T,S1), 
                  /* S1 — строка, образованная 
                    элементами списка T */
            frontchar(S,H,S1). 
                  /* S — строка, полученная 
                    дописыванием строки S1 
                    к первому элементу списка H */

Пример. Создадим предикат, который по строке и символу подсчитает количество вхождений этого символа в данную строку. Предикат будет иметь три аргумента: первые два — входные ( строка и символ), третий — выходной (количество вхождений второго аргумента в первый).

Решение, как обычно, будет рекурсивным. Рекурсия по строке, в которой ведется подсчет количества вхождений данного символа. Если строка пустая, то не важно, вхождения какого символа мы считаем, все равно ответом будет ноль. Это базис. Шагов рекурсии будет два в зависимости от того, будет ли первым символом строки символ, вхождения которого мы считаем, или нет. В первом случае нужно подсчитать, сколько раз искомый символ встречается в остатке строки, и увеличить полученное число на единицу. Во втором случае (когда первый символ строки отличен от символа, который мы считаем) увеличивать полученное число не нужно. При расщеплении строки на первый символ и хвост нужно воспользоваться уже знакомым нам предикатом frontchar.

char_count("",_,0). /* Любой символ не встречается 
                  в пустой строке ни разу*/
char_count(S,C,N):–
              frontchar(S,C,S1),!, 
                /* символ C оказался первым символом 
                  строки S, в S1 — оставшиеся 
                  символы строки S */
              char_count(S1,C,N1), 
                    /* N1 — количество вхождений 
                       символа C в строку S1 */
              N=N1+1. 
                /* N — количество вхождений 
                  символа C в строку S получается 
                  из количества вхождений символа C
                  в строку S1 добавлением единицы */
char_count(S,C,N):–
              frontchar(S,_,S1), 
                  /* первым символом строки S 
                    оказался символ, отличный
                    от исходного символа C, в S1 — 
                    оставшиеся символы строки S */
              char_count(S1,C,N). 
                  /* в этом случае количество 
                    вхождений символа C в строку S 
                    совпадает с количеством 
                    вхождений символа C 
                    в строку S1 */

Пример. Попробуем разработать предикат, который по символу и строке будет возвращать первую позицию вхождения символа в строку, если символ входит в строку, и ноль, если не входит. У предиката будет три параметра. Первые два — входные — символ и строка, третий — выходной — первая позиция вхождения первого параметра во второй параметр или ноль.

Не самая легкая задачка, но мы с ней справимся. Можно, конечно, записать в качестве базиса, что в пустой строке не встречаются никакие символы, но мы пойдем другим путем.

Вначале с помощью предиката frontchar разделим исходную строку на первый символ и остаток строки. Если первым символом строки окажется тот самый символ, позицию которого мы ищем, значит, больше ничего делать не нужно. Ответом будет единица. В этом случае нам даже неважно, какие символы оказались в хвосте строки, поскольку мы ищем первое вхождение данного символа в строку.

В противном случае, если первым символом исходной строки является какой-то символ, отличный от искомого, нам нужно искать позицию вхождения символа в остаток строки. Если искомый символ найдется в хвосте, позиция вхождения символа в исходную строку будет на единицу больше, чем позиция вхождения этого символа в остаток строки. Во всех остальных ситуациях наш символ не встречается в исходной строке и, следовательно, мы должны означить третий аргумент нулем.

Давайте попробуем записать эти рассуждения.

str_pos(C,S,1):–
          frontchar(S,C,_),!. 
                /* Искомый символ C оказался первым 
                  символом данной строки S */
str_pos(C,S,N) :–
          frontchar(S,_,S1), 
                /* S1 — состоит из всех символов 
                 строки S, кроме первого, который 
                 отличается от искомого символа C */
          str_pos(C,S1,N1), 
                /* N1 — это позиция, в которой
                  символ C встречается первый раз 
                  в хвосте S1 или ноль*/
          N1<>0,!, /* если позиция вхождения  
                   символа C в строку S1 не равна  
                   нулю, то есть если он встречается 
                   в строке S1, /
          N=N1+1. /* то, увеличив позицию его 
                  вхождения   на единицу, мы получим 
                  позицию его вхождения в исходную 
                  строку */
str_pos(_,_,0). /* искомый символ не входит в данную 
              строку */

Пример. Создадим предикат, который будет заменять в строке все вхождения одного символа на другой символ. У предиката будет четыре параметра. Первые три — входные (исходная строка ; символ, вхождения которого нужно заменять; символ, которым нужно заменять первый символ); четвертым — выходным — параметром должен быть результат замены в первом параметре всех вхождений второго параметра на третий параметр.

Решение, как обычно, будет рекурсивным. Если строка пустая, значит, в ней нет символов, и, следовательно, заменять нечего. Результатом будет тоже пустая строка. Если же строка непустая, то мы должны разделить ее с помощью предиката frontchar на первый символ и строку, состоящую из остальных символов исходной строки.

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

В первом случае заменим все вхождения первого символа вторым символом в хвосте исходной строки, после чего, опять-таки с помощью предиката frontchar, приклеим полученную строку ко второму символу. В итоге в результирующей строке все вхождения первого символа будут заменены вторым символом.

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

str_replace("",_,_,""):–!. /* из пустой строки можно 
                       получить только пустую 
                       строку */
str_replace(S,C,C1,SO):–
                frontchar(S,C,S1),!, 
                    /* заменяемый символ C оказался 
                       первым символом строки S, 
                       S1 — остаток строки S */
                str_replace(S1,C,C1,S2), 
                    /* S2 — результат замены 
                       в строке S1 всех вхождений 
                       символа C на символ C1 */
                frontchar(SO,C1,S2). 
                    /* SO — результат склейки 
                       символа C1 и строки S2 */
str_replace(S,C,C1,SO):–
                frontchar(S,C2,S1), 
                    /* разделяем исходную строку S 
                       на первый символ C2 
                       и строку S2, образованную 
                       всеми символами строки S, 
                       кроме первого */
                str_replace(S1,C,C1,S2), 
                      /* S2 — результат замены 
                        в строке S1 всех вхождений 
                        символа C на символ C1 */
                frontchar(SO,C1,S2). 
                      /* SO — результат соединения 
                        символа C1 и строки S2 */

Если нам понадобится предикат, который будет заменять не все вхождения первого символа на второй, а только первое вхождение первого символа, то нужно просто из первого правила удалить вызов предиката str_replace(S1,C,C1,S2).

< Лекция 10 || Лекция 11: 1234 || Лекция 12 >
Виктор Бондарь
Виктор Бондарь

После приведения формулы вида ПНФ к виду ССФ вы получаете формулу, в безквантовой матрице которой дизъюнкт содержит оба контранрных атома:. Как тогда проводить его унификацию, если в случае замены x на f(x) весь дизъюнкт обратится в единицу?

Ольга Потапенко
Ольга Потапенко

никак не могу увидеть тексты самих лекций.