2012-01-05 3 views
17

Просто посмотрел на Haskell и понял (насколько я могу судить) нет прямого способа проверить строку, чтобы увидеть, содержит ли она меньшую строку. Поэтому я решил, что я просто сделаю это.Есть ли лучший способ написать метод «string contains X»?

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

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

stringExists "" wordToCheckAgainst = False 
stringExists wordToCheckFor "" = False 
stringExists wordToCheckFor wordToCheckAgainst | length wordToCheckAgainst < length wordToCheckFor = False 
               | length wordToCheckAgainst == length wordToCheckFor = wordToCheckAgainst == wordToCheckFor 
               | take (length wordToCheckFor) wordToCheckAgainst == wordToCheckFor = True 
               | otherwise = stringExists wordToCheckFor (tail wordToCheckAgainst) 

ответ

41

Вы проверили Hoogle?

Если вы ищете подпись функции, которую ищете (String -> String -> Bool), вы должны увидеть isInfixOf среди лучших результатов.

+1

+1 для Hoogle. Это лучший друг всех кодов Haskell :) – Daenyth

+17

Изучение [источник 'isInfixOf'] (http://hackage.haskell.org/packages/archive/base/latest/doc/html/src/Data-List.html #isInfixOf) является поучительным. – dave4420

+0

@ dave4420 Ссылка не работает. – ThreeFx

23

isInfixOf из Data.List, безусловно, решить эту проблему, однако в случае длинных стога или perverse¹ игл вы должны рассмотреть более продвинутое string matching algorithms с намного лучше средней и худшим случаем сложностью.


¹ Рассмотрим действительно длинную строку, состоящую только из a-х и иглу с большим количеством a-х в начале и один b в конце.

+0

Обратите внимание, что для более эффективного алгоритма потребуется другая структура данных, чем' String' (или '[a]'). –

+3

Действительно, обычно требуется предварительная предварительная обработка входной строки. Однако реализовать их в способе, приводящем к функции '(String -> String -> Bool), абсолютно возможно. – Jan

+0

Если вы действительно заинтересованы в производительности, вы, вероятно, реализуете его следующим образом: [Data.Text.Search.indices] (http://hackage.haskell.org/packages/archive/text/latest/doc/html /src/Data-Text-Search.html#indices) (примечание 'Data.Text.isInfixOf' реализовано в терминах этого: из-за лени он может остановиться после того, как найден первый индекс) –

9

Рассмотрите возможность использования text package (text на Hackage, теперь также часть платформы Haskell) для ваших нужд обработки текста. Он предоставляет текстовый тип Unicode, который более эффективен по времени и пространству, чем встроенный в список String. Для поиска строк пакет textimplements a Boyer-Moore-based algorithm, который имеет лучшую сложность, чем наивный метод, используемый Data.List.isInfixOf.

Пример использования:

Prelude> :s -XOverloadedStrings 
Prelude> import qualified Data.Text as T 
Prelude Data.Text> T.breakOnAll "abc" "defabcged" 
[("def","abcged")] 
Prelude Data.Text> T.isInfixOf "abc" "defabcged" 
True 
+0

Нужно перегрузитьStrings только для проверки подстроки матчи - довольно противная бородавка. Альтернатива тому, чтобы обернуть «pack» и «unpack», действительно неудовлетворительна. – ely

Смежные вопросы