2009-12-08 72 views
2
替換使用正則表達式和反向引用串

我試圖從HTML轉換成乳膠,並想改變這一點:Clojure中

<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,其中有一個替換使用正則表達式的功能,但它似乎沒有處理反向引用。我錯過了什麼嗎?這是錯誤的方式嗎?任何幫助表示讚賞。

+0

關於在下面的答案中提到的正則表達式和HTML的不幸選擇,我反駁說這是一次性程序,而源是東西是以前由我編程生成。我認爲一個XML解決方案將是可持續性和可重用性的正確途徑,但在這一點上,我只是試圖一起破解它。 – 2009-12-08 13:27:26

回答

4

You should not parse HTML with a regex...

兩件事情:

  1. Java使用$1$2指捕捉組,不\1\2

  2. 在替換文本中需要更多反斜槓。 Clojure閱讀器消耗了第一級反斜槓,因爲它是一個字符串。正則表達式消耗了第二級反斜槓。不幸的是,Clojure沒有「原始」字符串文字的一般語法(還沒有?)。 Clojure文字正則表達式的語法#""會爲您節省一些反斜槓,但是普通的字符串沒有那種魔力。

所以:

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)幾乎相同。

+0

是否有理由通過s/replace選項選擇.replaceAll,反之亦然?看起來他們都應該工作,但是有更高的處理需求,還是更常用的Clojure? 給定相同的功能,最佳實踐是什麼? – 2009-12-08 13:30:08

+0

'clojure.contrib.str-utils2/replace'可以做更多的事情(你可以傳入一個fn作爲第三個參數)。但它是您項目的附加依賴項。它們都是慣用的,你不必迴避Java調用。我個人使用'str-utils'來處理大多數事情。 – 2009-12-08 17:52:12

1

如果你想真的很漂亮,你可以去clojure.xml。它會返回一個可以隨意修改的結構樹。你上面的例子是這樣的:

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

這可以很容易地轉換爲類似:

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

可以很容易地連載回你所希望的形式。最好的部分是:沒有不可維護的正則表達式。 :) YMMV當然.....