2012-08-30 28 views
1

我有一些行爲良好的xml文件,我想用regex重新格式化(不是PARSE!)。我們的目標是讓每個<trkpt>配對作爲線索。Python的正則表達式,以消除模式內的空白匹配

下面的代碼有效,但我希望在單個正則表達式替換而不是循環中執行操作,這樣我就不需要連接字符串了。

import re 

xml = """ 
    <trkseg> 
     <trkpt lon="-51.2220657617" lat="-30.1072524581"> 
     <time>2012-08-25T10:20:44Z</time> 
     <ele>0</ele> 
     </trkpt> 
     <trkpt lon="-51.2220657617" lat="-30.1072524581"> 
     <time>2012-08-25T10:20:44Z</time> 
     <ele>0</ele> 
     </trkpt> 
     <trkpt lon="-51.2220657617" lat="-30.1072524581"> 
     <time>2012-08-25T10:20:44Z</time> 
     <ele>0</ele> 
     </trkpt> 
    </trkseg> 
""" 

for trkpt in re.findall('<trkpt.*?</trkpt>', xml, re.DOTALL): 
    print re.sub('>\s*<', '><', trkpt, re.DOTALL) 

使用sed的答案也將受到歡迎。

感謝您閱讀

+0

是吧'trkseg'或要作爲一條線'trkpt'?你陳述'trkseg',但你的正則表達式在'trkpt'上工作... – KRyan

+0

另外,我認爲無論它是哪個,都不可能有嵌套的標籤類型?只要你有嵌套,正則表達式不能處理它。 – KRyan

+0

如果這是一個你所做的「快而髒」的腳本,而你不想分析xml,我會說for循環比瘋狂的正則表達式更簡單,更可讀。 –

回答

1

如何:

>>> regex = re.compile(
    r"""\n[ \t]* # Match a newline plus following whitespace 
    (?=   # only if... 
    (?:   # ...the following can be matched: 
     (?!<trkpt) # (unless an opening <trkpt> tag occurs first) 
     .   # any character 
    )*   # any number of times, 
    </trkpt>  # followed by a closing </trkpt> tag 
    )    # End of lookahead""", 
    re.DOTALL | re.VERBOSE) 
>>> print regex.sub("", xml) 

    <trkseg> 
     <trkpt lon="-51.2220657617" lat="-30.1072524581"><time>2012-08-25T10:20:44Z</time><ele>0</ele></trkpt> 
     <trkpt lon="-51.2220657617" lat="-30.1072524581"><time>2012-08-25T10:20:44Z</time><ele>0</ele></trkpt> 
     <trkpt lon="-51.2220657617" lat="-30.1072524581"><time>2012-08-25T10:20:44Z</time><ele>0</ele></trkpt> 
    </trkseg> 
+0

它並沒有爲我第一次工作。不得不從多行模式中刪除註釋,並刪除're.VERBOSE'標誌,如下所示:'regex = re.compile('\ n [\ t] *(?=(?:(?!)',re.DOTALL)'。然後,它的工作,但「吃」縮進(不是很大的問題,我打算相當打印結果)。 – heltonbiker

+0

@heltonbiker:對不起,當我將正則表達式改爲冗長的字符串時,我忘記了字符串的'r'前綴。現在它應該可以正常工作。對不起,我不早點回復,但是當你寫下你的評論時,已經過了午夜了,而我只是現在才閱讀。 –

1

這不是真的你問什麼,但這裏有一個襯爲被一個班輪着想:

>>> print re.sub(r'(<trkpt.*?</trkpt>)', 
       lambda m: re.sub(r'>\s*<', '><', m.group(1), re.DOTALL), 
       xml, flags=re.DOTALL) 

<trkseg> 
    <trkpt lon="-51.2220657617" lat="-30.1072524581"><time>2012-08-25T10:20:44Z</time><ele>0</ele></trkpt> 
    <trkpt lon="-51.2220657617" lat="-30.1072524581"><time>2012-08-25T10:20:44Z</time><ele>0</ele></trkpt> 
    <trkpt lon="-51.2220657617" lat="-30.1072524581"><time>2012-08-25T10:20:44Z</time><ele>0</ele></trkpt> 
</trkseg> 

另外請注意,這種方法將會中斷如果任何字符串屬性包含字符串"<trkpt",這可能不會發生,但這是不使用真正的解析器的問題。

+0

這是一個不錯的操作方法,但恐怕額外的棘手使代碼難以閱讀。不管怎麼說,還是要謝謝你! – heltonbiker

1

是否要保留<trkseg>?如果是這樣,這可能爲你工作:

print re.sub('([^gt])>\s*<', '\g<1>><', xml, re.DOTALL) 

刪除元素之間的所有空間,條件是前一個元素,不帶T和G結束。

<trkseg> 
    <trkpt lon="-51.2220657617" lat="-30.1072524581"><time>2012-08-25T10:20:44Z</time><ele>0</ele></trkpt> 
    <trkpt lon="-51.2220657617" lat="-30.1072524581"><time>2012-08-25T10:20:44Z</time><ele>0</ele></trkpt> 
    <trkpt lon="-51.2220657617" lat="-30.1072524581"><time>2012-08-25T10:20:44Z</time><ele>0</ele></trkpt> 
</trkseg> 
+0

它的工作原理!你能解釋一下/爲什麼這是有效的?這裏使用哪種正則表達式概念?我無法確定它在 ......的特定位置? – heltonbiker

+1

[^ tg]位匹配任何不是t或g的字符。它位於圓括號之間,所以無論匹配什麼字符都可以通過替換字符串中的\ g <1>添加。 – user711413

+1

是的,但仍然可以在其他文件中使用帶有'g'或't'的標籤來破壞該技巧...:o( – heltonbiker

0
另一個

一襯墊是

print re.sub("(<trkpt.+?>).*?(<time>.+?</time>).*?(<ele>.+?</ele>).*?(</trkpt>)", 
      r'\1\2\3\4', xml, re.DOTALL) 

產生

<trkseg> 
    <trkpt lon="-51.2220657617" lat="-30.1072524581"><time>2012-08-25T10:20:44</time><ele>0</ele></trkpt> 
    <trkpt lon="-51.2220657617" lat="-30.1072524581"><time>2012-08-25T10:20:44</time><ele>0</ele></trkpt> 
    <trkpt lon="-51.2220657617" lat="-30.1072524581"><time>2012-08-25T10:20:44</time><ele>0</ele></trkpt> 
</trkseg> 

這具有容易改變爲其它標籤的優點。

+1

不幸的是,我不想依賴關於內的標籤的具體訂單... – heltonbiker