написать строковую функцию сравнения

Я полностью понимаю использование списка в lisp, но у меня проблемы с использованием строки. Я пытаюсь написать свой собственный код функций, таких как string> или string‹, из common lisp, чтобы понять, как lisp работает со строками. Например, abcde больше, чем abbb, и возвращает 1.

Я думаю, что я буду использовать функцию char или вы думаете, что я должен использовать subseq? или функция, которая имеет дело с кодом ASCII?

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

Мне нужна помощь по поводу "перейти к следующему символу".

Большое спасибо !!


person lilawood    schedule 09.06.2011    source источник


Ответы (4)


Это реализация функции, которая для двух строк возвращает либо -1, 0, либо +1 в зависимости от того, является ли первая меньше, равна или больше второй. Если одна строка является начальной частью другой, то более короткая строка считается "меньше" более длинной.

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

(defun strcmp (a b)
  (do ((i 0 (1+ i))
       (na (length a))
       (nb (length b)))
      ((or (= i na) (= i nb) (char/= (elt a i) (elt b i)))
         (cond
           ((= i na nb) 0)                  ;; Strings are identical
           ((= i na) -1)                    ;; a finished first
           ((= i nb) 1)                     ;; b finished first
           ((char< (elt a i) (elt b i)) -1) ;; Different char a < b
           (t 1)))))                        ;; Only remaining case

(defun test (a b)
  (format t "(strcmp ~s ~s) -> ~s~%"
          a b (strcmp a b)))

(test "abc" "abc")
(test "ab"  "abc")
(test "abc" "ab")
(test "abd" "abc")
(test "abc" "abd")

Выход

(strcmp "abc" "abc") -> 0
(strcmp "ab" "abc") -> -1
(strcmp "abc" "ab") -> 1
(strcmp "abd" "abc") -> 1
(strcmp "abc" "abd") -> -1
person 6502    schedule 12.06.2011
comment
Спасибо ! Я понимаю, как это работает. Последний вопрос: что такое na и nb (строки 3/4), они содержат значения (длина a) и (длина b), если я прав? - person lilawood; 16.06.2011

Это версия Common Lisp. Вы можете просто использовать ELT, потому что

(type-of "a") => (SIMPLE-ARRAY CHARACTER (1))

(defun my-string< (a b &key (start 0))
  (cond
    ((= start (length a) (length b))
     nil)
    ((>= start (min (length a) (length b)))
     (error "Undefined"))
    ((char= (elt a start) (elt b start))
     (my-string< a b :start (1+ start)))
    ((char< (elt a start) (elt b start))
     t)))
person Mark Cox    schedule 09.06.2011
comment
Спасибо ! Я начинаю понимать, как это работает. Но у меня проблемы с пониманием :start и min, и я не нашел этого в документации по lisp. - person lilawood; 11.06.2011
comment
min — это просто числовой минимум, т. е. он возвращает наименьший из своих аргументов. :start является аргументом ключевого слова для my-string<. - person smackcrane; 12.06.2011
comment
Почему этот код считает ошибкой сравнение, скажем, "ab" с "abc"? - person 6502; 13.06.2011
comment
START — это параметр ключевого слова. gigamonkeys.com/book/functions.html Его цель состояла в том, чтобы позволить запустить предикат в любой позиции строки. Я не уверен в полезности аргумента для абонентов MY-STRING‹. Однако это удобно для реализации MY-STRING‹. Если вы считаете, что START не имеет значения для MY-STRING‹, вы всегда можете скрыть рекурсивный вызов функции в блоке LABELS. - person Mark Cox; 14.06.2011
comment
Функция MIN определена в Common Lisp Hyperspec. Его можно найти здесь: lispworks.com/documentation/HyperSpec/Front/Contents. htm Определение MIN находится здесь lispworks.com/documentation/HyperSpec. /Body/f_max_m.htm - person Mark Cox; 14.06.2011
comment
Причина, по которой при сравнении ab и abc сообщается об ошибке, заключается в том, что Лилавуд никогда не объявлял, какое значение должны принимать несуществующие символы, то есть отрицательная бесконечность или положительная бесконечность. Я вижу, что вы выбрали отрицательную бесконечность, что прекрасно и, вероятно, наиболее интуитивно понятно. Я предпочел явно показать Лилавуд, что необходимо принять другое решение или контрольный пример. - person Mark Cox; 14.06.2011

Ваша проблема уже решена, но если вы столкнетесь с другими, может быть полезен следующий метод:

Я установил SBCL из исходного кода и храню исходный код. Это позволяет мне запускать M-. на имя функции, такое как string‹, и она перейдет к определению в вашей реализации lisp.

В моем случае я остановился на этом макросе:

;;; LESSP is true if the desired expansion is for STRING<* or STRING<=*.
;;; EQUALP is true if the desired expansion is for STRING<=* or STRING>=*.
(sb!xc:defmacro string<>=*-body (lessp equalp)
  (let ((offset1 (gensym)))
    `(with-two-strings string1 string2 start1 end1 ,offset1 start2 end2
       (let ((index (%sp-string-compare string1 start1 end1
                                        string2 start2 end2)))
         (if index
             (cond ((= (the fixnum index) (the fixnum end1))
                    ,(if lessp
                         `(- (the fixnum index) ,offset1)
                       `nil))
                   ((= (+ (the fixnum index) (- start2 start1))
                       (the fixnum end2))
                    ,(if lessp
                         `nil
                       `(- (the fixnum index) ,offset1)))
                   ((,(if lessp 'char< 'char>)
                     (schar string1 index)
                     (schar string2 (+ (the fixnum index) (- start2 start1))))
                    (- (the fixnum index) ,offset1))
                   (t nil))
             ,(if equalp `(- (the fixnum end1) ,offset1) nil))))))
) ; EVAL-WHEN
person whoplisp    schedule 01.07.2011

В схеме нет прямого понятия итерации ("следующей") со строками. Это относится только к спискам. Поэтому вместо этого вам нужно перебирать индексы:

(define (string<? lhs rhs)
  (let* ((lhslen (string-length lhs))
         (rhslen (string-length rhs))
         (minlen (min lhslen rhslen)))
    (let loop ((i 0))
      (if (= i minlen) (< lhslen rhslen)
          (let ((lhschar (string-ref lhs i))
                (rhschar (string-ref rhs i)))
            (cond ((char<? lhschar rhschar) #t)
                  ((char<? rhschar lhschar) #f)
                  (else (loop (+ i 1)))))))))
person Chris Jester-Young    schedule 09.06.2011
comment
Ого, провал. Я не понимал, что этот вопрос - вопрос [общий], а не [схема]. Во всяком случае, я продолжу, чтобы проиллюстрировать принцип. - person Chris Jester-Young; 10.06.2011