String Clojure中的简单模式匹配

String Clojure中的简单模式匹配,string,clojure,pattern-matching,String,Clojure,Pattern Matching,我在Clojure中有一个字符串,我想命名和提取匹配的各个部分。执行此操作的标准方法是: (re-seq #"\d{3}-\d{4}" "My phone number is 000-1234") ;; returns ("000-1234") 但是,我希望能够命名和访问匹配的部分 下面是一个例子: (def mystring "Find sqrt of 6 and the square of 2") (def patterns '(#"sqrt of \d" #"square of \d")

我在Clojure中有一个字符串,我想命名和提取匹配的各个部分。执行此操作的标准方法是:

(re-seq #"\d{3}-\d{4}" "My phone number is 000-1234")
;; returns ("000-1234")
但是,我希望能够命名和访问匹配的部分

下面是一个例子:

(def mystring "Find sqrt of 6 and the square of 2")
(def patterns '(#"sqrt of \d" #"square of \d"))
当我在
mystring
上匹配我的模式列表时,我希望结果类似于
{:sqrt 6,:root 2}

更新


我发现一个名为的第三方软件包支持命名组,但我希望在核心库中有一个解决方案。

您需要捕获所需的模式,例如:

(re-seq #"sqrt of (\d)" "Find sqrt of 6")
或者,如果您希望第一组匹配:

(def matcher #"sqrt of (\d)" "Find sqrt of 6")
(re-find matcher)
(second (re-groups matcher))
有关详细信息,请参阅文档


至于命名捕获的组,我没有仔细查看您在问题中提到的库,但我认为唯一实际的区别在于为捕获组指定一个名称,而不是仅通过其从左到右的数字位置引用(从1开始)在正则表达式中。

您需要捕获所需的模式,例如:

(re-seq #"sqrt of (\d)" "Find sqrt of 6")
或者,如果您希望第一组匹配:

(def matcher #"sqrt of (\d)" "Find sqrt of 6")
(re-find matcher)
(second (re-groups matcher))
有关详细信息,请参阅文档


至于命名捕获的组,我没有仔细查看您在问题中提到的库,但我认为唯一实际的区别在于为捕获组指定一个名称,而不是仅通过其从左到右的数字位置引用(从1开始)在正则表达式中。

可以使用java正则表达式的命名组来完成。问题是没有api来获取所有组的名称,因此您必须从regexp获取它们:

(defn find-named [re s]
  (let [m (re-matcher re s)
        names (map second (re-seq #"\(\?<([\w\d]+)>" (str re)))]
    (when (.find m)
      (into {} (map (fn [name]
                      [(keyword name) (.group m name)])
                    names)))))

您可以使用java正则表达式的命名组来实现。问题是没有api来获取所有组的名称,因此您必须从regexp获取它们:

(defn find-named [re s]
  (let [m (re-matcher re s)
        names (map second (re-seq #"\(\?<([\w\d]+)>" (str re)))]
    (when (.find m)
      (into {} (map (fn [name]
                      [(keyword name) (.group m name)])
                    names)))))

根据您打算对“命名匹配”执行的操作,您可能会发现简单地分解匹配并将其绑定到符号上也很有用

对于单个匹配:

(if-let [[_ digit letter] (re-find #"(\d)([a-z])" "1x 2y 3z")]
  [digit letter])  ; => ["1" "x"]
对于多个匹配:

(for [[_ digit letter] (re-seq #"(\d)([a-z])" "1x 2y 3z")]
  [digit letter])  ; => (["1" "x"] ["2" "y"] ["3" "z"])

根据您打算对“命名匹配”执行的操作,您可能会发现简单地分解匹配并将其绑定到符号上也很有用

对于单个匹配:

(if-let [[_ digit letter] (re-find #"(\d)([a-z])" "1x 2y 3z")]
  [digit letter])  ; => ["1" "x"]
对于多个匹配:

(for [[_ digit letter] (re-seq #"(\d)([a-z])" "1x 2y 3z")]
  [digit letter])  ; => (["1" "x"] ["2" "y"] ["3" "z"])

这对我不管用。它给出了IllegalStateException找不到匹配的java.util.regex.Matcher.group(Matcher.java:536)我更新了答案-主要是
\d
Ok周围的参数,所以现在它返回([“sqrt of 6”“6”]),但我不能保证最后一个元素就是我想要的。我认为我们需要“命名模式”。重组的回报是一个向量。第一个要素是整个匹配。剩下的元素是特定的匹配项。谢谢。因此,命名组是我的目标,我添加了一个链接到该项目。核心库中是否内置了类似的东西,可以在列表和字符串中使用?这对我不适用。它给出了IllegalStateException找不到匹配的java.util.regex.Matcher.group(Matcher.java:536)我更新了答案-主要是
\d
Ok周围的参数,所以现在它返回([“sqrt of 6”“6”]),但我不能保证最后一个元素就是我想要的。我认为我们需要“命名模式”。重组的回报是一个向量。第一个要素是整个匹配。剩下的元素是特定的匹配项。谢谢。因此,命名组是我的目标,我添加了一个链接到该项目。核心库中是否内置了类似的东西,可以在列表和字符串中工作?很好。有没有类似的东西可以象征性地在列表上工作,比如“(6的sqrt,2的平方)?我真的不知道,是否有任何lib存在,但在简单的情况下,您总是可以将此列表转换为字符串并使用regexp,
(pr str)(6的sqrt,2的平方))
=>
(6的sqrt,2的平方)
另外,如果你知道列表的结构,你可以对它进行一些特定的解析,比如在你的例子中,它是
(进入{}(对于[[k_v](分区3'(sqrt of 6,square of 2))][(关键字k)v]))
我真的认为这里不需要通用的东西。我的用例实际上是OR:
(查找命名为#“(sqrt of(?\d))|(平方(?\d))“求6的sqrt和fff的平方”)
这很好地给出了
{:sqrt“6”,:root nil}
Nice。有没有类似的东西可以象征性地在列表上工作,比如“(6的sqrt,2的平方)?我真的不知道,是否有任何lib存在,但在简单的情况下,您总是可以将此列表转换为字符串并使用regexp,
(pr str)(6的sqrt,2的平方))
=>
(6的sqrt,2的平方)
另外,如果你知道列表的结构,你可以对它进行一些特定的解析,比如在你的例子中,它是
(进入{}(对于[[k_v](分区3'(sqrt of 6,square of 2))][(关键字k)v]))
我真的认为这里不需要通用的东西。我的用例实际上是OR:
(查找命名为#“(sqrt of(?\d))|(平方(?\d))“求6的sqrt和fff的平方”)
这很好地给出了
{:sqrt“6”,:root nil}