Common Lisp: функция удаления, как она используется? - PullRequest
5 голосов
/ 21 марта 2009

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

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

Я установил request-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)

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

Ответы [ 4 ]

4 голосов
/ 21 марта 2009

Научитесь читать 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 - это персонаж. # \ узел не является символом. Нелегальная. Строка "/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 для # /.

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

Также (удалить "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.

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

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

2 голосов
/ 21 марта 2009

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

(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, библиотеку регулярных выражений.

2 голосов
/ 21 марта 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, вы уже загрузили первый.)

0 голосов
/ 21 марта 2009

Сбой, потому что "/" это строка, а не символ.

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

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

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

Но, как вы можете видеть, он удалит все косые черты. Согласно странице документа, на которую вы ссылаетесь, удаление принимает ключевое слово param с именем: count, которое говорит, сколько элементов нужно удалить. Так что вы могли бы сделать это.

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

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

:: EDIT ::

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

...