Я пытаюсь извлечь ВСЕ разрешения экрана телефона из XML файла WURFL с помощью ниже Python script. Проблема в том, что я получаю только первый матч. Зачем? Как я могу получить все совпадения?
XML файл WURFL можно найти по адресу http://sourceforge.net/projects/wurfl/files/WURFL/latest/wurfl-latest.zip/download?use_mirror=freefr
def read_file(file_name):
f = open(file_name, 'rb')
data = f.read()
f.close()
return data
text = read_file('wurfl.xml')
import re
pattern = '<device id="(.*?)".*actual_device_root="true">.*<capability name="resolution_width" value="(\d+)"/>.*<capability name="resolution_height" value="(\d+)"/>.*</device>'
for m in re.findall(pattern, text, re.DOTALL):
print(m)
Сначала используйте синтаксический анализатор XML вместо регулярных выражений. В долгосрочной перспективе вы будете счастливее.
Во-вторых, если вы настаиваете на использовании регулярных выражений, используйте finditer()
вместо findall()
.
В-третьих, ваше регулярное выражение совпадает с первой записью до последней (.*
является жадным, и вы установили режим DOTALL
), поэтому либо увидите первый абзац, либо, по крайней мере, измените ваше регулярное выражение на
pattern = r'<device id="(.*?)".*?actual_device_root="true">.*?<capability name="resolution_width" value="(\d+)"/>.*?<capability name="resolution_height" value="(\d+)"/>.*?</device>'
Также всегда используйте необработанные строки с регулярными выражениями. \d
срабатывает, \b
будет вести себя неожиданно в "нормальной" строке.
Я, конечно, не прочь обращаться с xml с регулярным выражением, если требования просты, но, возможно, в этом случае использование реального анализатора XML будет лучше. Используя модуль stdlib etree и разбрызгивание (imho) отвратительных xpaths:
import xml.etree.ElementTree as ET
def capability_value(cap_elem):
if cap_elem is None:
return None
return int(cap_elem.attrib.get('value'))
def devices(wurfl_doc):
for el in wurfl_doc.findall("/devices/device[@actual_device_root='true']"):
width = el.find("./group[@id='display']/capability[@name='resolution_width']")
width = capability_value(width)
height = el.find("./group[@id='display']/capability[@name='resolution_height']")
height = capability_value(height)
device = {
'id' : el.attrib.get('id'),
'resolution' : {'width': width, 'height': height}
}
yield device
doc = ET.ElementTree(file='wurfl.xml')
for device in devices(doc):
print device
Вы используете "жадные" совпадения: .*
будет соответствовать количеству текста, которое он может захватить, что означает, что .*
до <capabilities>
соответствует большей части файла.
text = open('wurfl.xml').read()
pattern = r'<device id="(.*?)".*?actual_device_root="true">.*?<capability name="resolution_width" value="(\d+)"/>.*?<capability name="resolution_height" value="(\d+)"/>.*?</device>'
for m in re.findall(pattern, text, re.DOTALL):
print m
Это нечетность в поведении findall
, в частности findall
возвращает только первую сопоставимую группу из каждого совпадения шаблонов. См. этот вопрос.