2012-05-04 77 views
0

我試圖用AndroidManifest.xml替換頻道名來批量生成一組用於發佈的頻道apk包。用匹配組python正則表達式替換

<meta-data android:value="CHANNEL_NAME_TO_BE_DETERMINED" android:name="UMENG_CHANNEL"/> 從一個xml文件。

通道CONFIGS被保存在配置文件中,某事像:

channel_name output_postfix valid 
"androidmarket" "androidmarket" true 

這裏是我的嘗試:

manifest_original_xml_fh = open("../AndroidManifest_original.xml", "r") 
manifest_xml_fh = open("../AndroidManifest.xml", "w") 
pattern = re.compile('<meta-data\sandroid:value=\"(.*)\"\sandroid:name=\"UMENG_CHANNEL\".*') 
for each_config_line in manifest_original_xml_fh: 
    each_config_line = re.sub(pattern, channel_name, each_config_line) 
    print each_config_line 

它取代了整個<meta-data android:value="CHANNEL_NAME_TO_BE_DETERMINED" android:name="UMENG_CHANNEL"/>androidmarket這顯然不是我的需要。然後我發現問題是pattern.match(each_config_line)返回一個匹配結果,其中一個結果組是「CHANNEL_NAME_TO_BE_DETERMINED」。我也試着給一些替換實現函數,但仍然失敗。

因此,由於我已經成功找到了模式,我該如何正確地替換匹配的結果組元素?

+0

我現在沒有你想要做的過程,那麼你的預期輸出是什麼?我認爲你的誤解是,所有匹配的東西都會被取代。如果你想從模式中保留東西,你必須捕獲它並重新插入替換字符串。 (或者通過使用lookaround斷言來匹配那些東西) – stema

+0

爲了使問題更加清楚,我想提一提:CHANNEL_NAME_TO_BE_DETERMINED在這裏是動態的,我需要的是將其替換爲某些有歧義的通道名稱。 – David

回答

0

我想你的誤解是,所有匹配的東西都會被取代。如果你想從模式中保留東西,你必須捕獲它並重新插入替換字符串。

或者你要使用環視斷言

更換試試這個

pattern = re.compile('(?<=<meta-data\sandroid:value=\")[^"]+') 
for each_config_line in manifest_original_xml_fh: 
    each_config_line = re.sub(pattern, channel_name, each_config_line) 

(?<=<meta-data\sandroid:value=\")是一個積極的向後斷言,它保證了這個文本是以前,但不匹配只有什麼比賽它(所以它不會被替換)

[^"]+然後將匹配任何不是"

看到它here on Regexr

+0

非常簡潔有效的解決方案。從來沒有聽說過積極的看後面的斷言,現在已經知道了。感謝那。 – David

0

要捕捉你需要改變正則表達式的元數據標籤的只是價值:

<meta-data\sandroid:value=\"([^"]*)\"\sandroid:name=\"UMENG_CHANNEL\".* 

具體來說,我改變了這一部分:

\"(.*)\" - 這是一個貪婪的匹配,所以它將繼續和儘可能多的字符匹配越好,只要表達的其他部分相匹配

\"([^"]*)\" - 這將匹配任何不是雙引號的內容。匹配結果將仍然在第一個捕獲組

如果你想做替換的事情,一個更好的想法可能是捕獲你想保持不變 - 我不是一個Python專家,但像這樣的東西可能會工作:

re.sub(r'(<meta-data\sandroid:value=\")[^"]*(\"\sandroid:name=\"UMENG_CHANNEL\".*)' 
, r'\1YourNewValue\2', s) 

\1是引用1 - 即它獲得的第一個捕獲組所匹配的

+0

:謝謝你的回覆。我做的比賽似乎沒有問題。匹配的結果組元素是CHANNEL_NAME_TO_BE_DETERMINED,我想要做的就是將這個匹配的結果組元素替換爲某個通道名稱。 – David

+0

適合您的第二個解決方案。 – David

1

我提出一個不同的方法:你的XML保存爲模板,用佔位符與標準Python來代替字符串操作。

E.g.

AndroidManifest_template.xml: 

<meta-data android:value="%(channel_name)s" android:name="UMENG_CHANNEL"/> 

python: 

manifest_original_xml_fh = open("../AndroidManifest_template.xml", "r") 
manifest_xml_fh = open("../AndroidManifest.xml", "w") 
for each_config_line in manifest_original_xml_fh: 
    each_config_line = each_config_line % {'channel_name': channel_name} 
    print each_config_line 
+0

很好的解決方法。其實,這就是我所做的。我只是很好奇如何直接解決它。 – David