在Clojure中使用正则表达式和反向引用替换字符串

时间:2009-12-08 03:57:38

标签: java regex clojure

我正在尝试将HTML转换为Latex,并希望更改此内容:

<a href="www.foo.com/bar">baz</a> 

成:

baz\footnote{www.foo.com/bar}

我想生成一个Clojure函数来获取一大块文本,并替换给定段落中存在的匹配项。

我试过

(.replaceAll 
    "<a href=\"foo.com\">baz</a>" 
    "<a.*href=\"(.*)\">(.*)</a>" 
    "\2\\footnote{\1}")

但是返回:

"^Bfootnote{^A}"

我还查看了clojure.contrib.str-utils2,它有一个使用正则表达式的替换函数,但它似乎不处理反向引用。我错过了什么吗?走错了路?任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:4)

You should not parse HTML with a regex...

两件事:

  1. Java使用$1$2来引用捕获组,而不是\1\2

  2. 替换文本中需要更多反斜杠。第一级反斜杠由Clojure读取器消耗,因为它是一个文字字符串。正则表达式消耗了第二级反斜杠。不幸的是,Clojure没有“原始”字符串文字的一般语法(但是?)。 Clojure文字正则表达式语法#""可以为你节省一些反斜杠,但正常的字符串没有那种魔力。

  3. 所以:

    user> (.replaceAll "<a href=\"www.foo.com/bar\">baz</a>"
                       "<a.*href=\"(.*)\">(.*)</a>"
                       "$2\\\\footnote{$1}")
    "baz\\footnote{www.foo.com/bar}"
    

    你也可以这样做:

    user> (require '(clojure.contrib [str-utils2 :as s]))
    nil
    user> (s/replace "<a href=\"www.foo.com/bar\">baz</a>"
                     #"<a.*href=\"(.*)\">(.*)</a>"
                     (fn [[_ url txt]]
                         (str txt "\\\\footnote{" url "}")))
    "baz\\footnote{www.foo.com/bar}"
    

    "\2"是一个控制字符(ASCII字符2),这就是它显示为^B的原因。与(char 2)几乎相同。

答案 1 :(得分:1)

如果你想变得非常漂亮,你可以选择clojure.xml。它将返回一个您可以根据需要修改的结构树。您的上述示例如下所示:

{:tag :a :attrs {:href "www.foo.com/bar"} :content ["bar"]}

这可以很容易地翻译成:

["bar" {:footnote "www.foo.com/bar"}]

可以轻松地序列化为您想要的形式。最好的部分:没有不可维护的正则表达式。 :) YMMV当然.....