python正则表达式替换匹配组

时间:2012-05-04 07:09:33

标签: python regex

我正在尝试替换AndroidManifest.xml的频道名称,批量生成一组频道apk包以供发布。

<meta-data android:value="CHANNEL_NAME_TO_BE_DETERMINED" android:name="UMENG_CHANNEL"/> 来自xml文件。

频道配置保存在配置文件中,如:

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”。我也试过给一些替换实现函数,但仍然失败了。

所以,既然我已成功找到模式,我该如何正确替换匹配的结果组元素?

3 个答案:

答案 0 :(得分: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

答案 1 :(得分: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 - 即它获得第一个捕获组匹配的内容

答案 2 :(得分: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=\")是一个积极的lookbehind断言,它确保此文本在之前,但不匹配(因此不会被替换)

然后

[^"]+将匹配任何非"

的内容

here on Regexr