Common Lisp: функция удаления, как она используется?

У меня есть запрос request-uri в виде «/ node / 143» (просто пример формата).

Я хочу убрать первую косую черту из строки, я нашел функцию удалить и попробовал. Я просто не могу заставить его работать (я использую SBCL в Linux).

Я установил запрос-uri, используя этот код.

(setq request-uri "/node/143")

Когда я проверяю переменную, я возвращаю ее.

request-uri
"/node/143"

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

(remove "/" request-uri)
"/node/143"

(remove '/ request-uri)
"/node/143"

Я даже пытался составить список

(remove '("/") request-uri)
"/node/143"

(remove '('/) request-uri)
"/node/143"

Хотя строки являются векторами символов Я подумал, что, может быть, вся строка может быть помещена в одну ячейку, и я попытался удалить все это, но все равно не повезло.

(remove "/node/143" request-uri)
"/node/143"

(remove '/node143 request-uri)
"/node/143"

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

Может ли кто-нибудь пролить свет на то, что здесь происходит?

Спасибо.

Изменить: я нашел ответ на свой вопрос, в связи с которым возник еще один вопрос.

Чтобы удалить элемент из строки, я использовал

(remove #\/ request-uri)

А как насчет целой строки

`(remove #\node request-uri`)

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

(remove "node" request-uri)
(remove 'node request-uri)
(remove ?\node request-uri)
(remove #\node request-uri)
(remove '("node") request-uri)

Я не уверен, как еще это можно решить здесь.


person BlueBadger    schedule 21.03.2009    source источник
comment
В случае сомнений используйте HyperSpec в качестве справочника для языка Common Lisp. CLtL2 устарел. Он описывает Common Lisp до завершения работы над стандартом. HyperSpec основан на окончательном стандарте ANSI CL.   -  person Rainer Joswig    schedule 22.03.2009


Ответы (4)


Научитесь читать Common Lisp HyperSpec.

Строки - это последовательности, Массивы (одномерные векторы символов) и, ну, Строки. Это означает, что применимы большинство из этих функций.

Давайте посмотрим на УДАЛИТЬ. CLHS дает такую ​​подпись:

remove item sequence &key from-end test test-not start end count key
    => result-sequence

Строки - это последовательности символов. Таким образом, призыв к удалению будет таким:

(remove #\/ "/foo/")

или (например)

(remove #\/ "/foo/" :start 2)

Помните: #\a - это персонаж. #\node не является символом. Незаконно. Строка "/foo/".

Элемент, который нужно УДАЛИТЬ из строки, должен быть символом. Ничего больше. Почему? Поскольку TEST по умолчанию является EQL, и EQL сравнивает символ в строке с аргументом вашего элемента. Также ключ по умолчанию IDENTITY и не меняет элементы.

Что, если ваш аргумент - строка? Что ж, тогда вам нужно сделать больше:

 (remove "/" "/abc/" :key #'string :test #'equal)

Это проверяет каждый символ последовательности и превращает его в строку. Затем строка будет сравнена с вашим элементом "/" с помощью функции EQUAL. Это тоже работает. Стоимость состоит в том, что ему необходимо сгенерировать строку из каждого символа "/abc/", каждая строка - это новый объект.

Другой способ сделать это:

 (remove "/" "/abc/" :test (lambda (a b) (eql (aref a 0) b)))

Вышеупомянутый извлекает первый символ "/" в каждом тесте и сравнивает его с символом из строки "/abc/". Опять же, цена состоит в том, что ему нужно получить персонажа пять раз (в этом примере).

Итак, лучший способ написать это, если ваш исходный объект представлен в виде строки:

(remove (aref "/" 0) "/abc/")

Выше мы получаем символ из строки "/" один раз, а затем REMOVE сравнивает этот символ с тестом EQL по умолчанию с каждым символом в строке - он возвращает новую строку тех символов, которые не являются EQL, с #\/.

Что вы ожидаете от? \ Foo? В Common Lisp это символ |?fOO|.

Также (remove "foo" "afoob") не работает, поскольку строка (здесь "foo") не является элементом строки. Помните, что символы - это элементы строк. Помните также, что строки с одним элементом, например "/", по-прежнему являются строками, а не символом. Таким образом, "/" и #\/ относятся к разным типам. Первый - это строка, а второй - это символ.

SUBSEQ извлекает последовательность из последовательности. Это означает, что он также извлекает строку из другой строки:

(subseq "0123456" 1 5)
     where 1 is the start and 5 is the end index.

CONCATENATE добавляет последовательности. Это означает, что он также добавляет строки.

(concatenate 'string "abc" "123")
  returns a new string with the strings "abc" and "123" appended.

Чтобы удалить части строки, см. Также функции STRING-TRIM, STRING-LEFT-TRIM и STRING-RIGHT-TRIM.

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

ПОИСК ищет строки в строках.

person Rainer Joswig    schedule 21.03.2009
comment
Прочтите мой пост внимательнее, я прочитал мануал, причем хорошо отформатированный. cs.cmu.edu/Groups/AI/html/ cltl / clm / node144.html - person BlueBadger; 22.03.2009
comment
Не используйте CLtL2 в качестве первого источника. Это устарело. HyperSpec основан на стандарте ANSI. CLtL2 нет. CLtL2 описывает некоторую языковую версию в процессе стандартизации до завершения работы. - person Rainer Joswig; 22.03.2009

Чтобы удалить всю подстроку, вам нужно будет создать новую функцию, например:

(defun remove-string (rem-string full-string &key from-end (test #'eql)
                      test-not (start1 0) end1 (start2 0) end2 key)
  "returns full-string with rem-string removed"
  (let ((subst-point (search rem-string full-string 
                             :from-end from-end
                             :test test :test-not test-not
                             :start1 start1 :end1 end1
                             :start2 start2 :end2 end2 :key key)))
    (if subst-point
        (concatenate 'string
                     (subseq full-string 0 subst-point)
                     (subseq full-string (+ subst-point (length rem-string))))
        full-string)))

Это только отправная точка. Я воспроизвел все варианты ПОИСКА, но я думаю, что некоторые варианты не имеют смысла в этом контексте. По крайней мере, это работает:

(remove-string "node" "this is a node or not")

Для более сложных случаев вам, возможно, стоит взглянуть на cl-ppcre, библиотеку регулярных выражений.

person Svante    schedule 21.03.2009

Объяснение:

(remove "node" request-uri)
(remove 'node request-uri)
(remove ?\node request-uri)
(remove #\node request-uri)
(remove '("node") request-uri)

Это (соответственно): строка, (заключенный в кавычки) символ, (оцененный) символ, искаженный символьный литерал и список, содержащий одну строку. REMOVE удаляет объект из последовательности объектов, а строка не является последовательностью этих вещей.

Если вы просто хотите удалить часть строки, SUBSEQ может помочь:

(let ((uri "/node/143"))
  (when (string= (subseq uri 0 6) "/node/")
    (format t "user wants node ~D" (parse-integer (subseq uri 6)))))

Для более сложных вещей вам, вероятно, понадобится библиотека, такая как cl-ppcre и / или split-sequence. (Если вы используете Hunchentoot, первый у вас уже загружен.)

person Anonymous Coward    schedule 21.03.2009

Это не удается, потому что «/» - это строка, а не символ.

(remove "/" request-uri)
"/node/143"

Если вам нужен символ, вам нужно использовать # /, т.е. символ косой черты.

(remove #\/ request-uri)
"node143"

Но, как видите, он удалит все косые черты. В соответствии со страницей документа, на которую вы ссылаетесь, remove принимает параметр ключевого слова с именем: count, который говорит, сколько элементов нужно удалить. Итак, вы могли это сделать.

(remove #\/ request-uri :count 1)
"node/143"

Надеюсь это поможет.

::РЕДАКТИРОВАТЬ::

Это не? /, Это # /. Спасибо, Дуглас!

person Tung Nguyen    schedule 21.03.2009
comment
Скопировал ваш код точно так, как он появился, получил эту ошибку: переменная? / Не связана. # \ / работает, как я редактировал выше. - person BlueBadger; 21.03.2009
comment
? \ / не является символом. Символ # \ /. - person Rainer Joswig; 21.03.2009