Расширить регулярные выражения Clojure с помощью IFn для поддержки карты - PullRequest
0 голосов
/ 26 ноября 2018

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

(map #"ab+c*" ["abbb" "ac" "abbcc"])
=> ("abbb" "abbcc")

Как расширить регулярные выражения для поддержки интерфейса IFn?Или есть другой способ сделать это?

Ответы [ 4 ]

0 голосов
/ 26 ноября 2018

Как говорит CmdrDats, использование re-find в анонимной функции - определенно верный путь:

(filter #(re-find #"ab+c*" %) ["abbb" "ac" "abbcc"]) 

    => ("abbb" "abbcc")

Иногда я использую вспомогательную функцию, чтобы подчеркнуть, что я хочу получить только истину / ложь (несовпадение или последовательность совпадений), и так как я всегда забываю различия между re-xxx функциями:

(ns demo.core
  (:require [schema.core :as s]))

(s/defn contains-match?  :- s/Bool
  "Returns true if the regex matches any portion of the intput string."
  [search-str :- s/Str
   re :- s/Any]
  #?(:clj (assert (instance? java.util.regex.Pattern re)))
  (boolean (re-find re search-str)))
0 голосов
/ 26 ноября 2018

Проблема с попытками сделать это состоит в том, что не совсем очевидно, что вы пытаетесь делать с регулярным выражением - особенно когда большая часть вашего производственного кода будет выглядеть как (map #"ab+" entries)

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

Если это один раз, просто используйте

(map #(clojure.string/replace % #"ab+c*" "ab") ["ab" "ac" "abbcc"])

=> ("ab" "ac" "ab")

(Не сразу очевидно, как должен работать ваш пример? У вас меньше элементов в результате - вы фильтруете и преобразование? Как вы попадаете на элемент «abbb»?)

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

0 голосов
/ 26 ноября 2018

Поскольку IFn не является протоколом в ядре Clojure, я не верю, что это возможно.

Самое близкое, что я могу получить, - это создание типа оболочки, реализующего IFn:

(defrecord R [^java.util.regex.Pattern regex]
  clojure.lang.IFn
  (invoke [this s]
    (re-find regex s))
  (invoke [this replacement s]
    (clojure.string/replace s regex replacement)))

(map (->R #"abc+") ["abcccc" "abcccccccc"])

=> ("abcccc" "abcccccccc")
0 голосов
/ 26 ноября 2018

ClojureScript:

(extend-type js/RegExp
  IFn
  (-invoke
    ([match s] (re-find match s))
    ([match replacement s]
      (clojure.string/replace s match replacement))))

Теперь вы можете вызывать регулярные выражения как функции и даже передавать их в map:

(#"abc+" "abcccc")
=> "abcccc"

(map #"abc+" ["abcccc" "abcccccccc"])
=> ("abcccc" "abcccccccc")

К сожалению, IFn не является протоколом вClojure, так что вы не можете расширить его.Это прискорбно.

...