正则表达式解析xml的可能性
2015-04-25
目标
我们要不使用第三方xml解析库, 自己编写C++代码解析 <skin name="test_bg" src="test.bmp" subwidth="0" top="10" left="10"></skin>
.
python re
虽然我们可以用字符串那套方法慢慢一步一步地提取出来, 但是直觉上, 这里应该可以用上正则表达式. 方便起见, 我们用python先试下, 毕竟python标准库就有正则表达式, C++11才在标准库带正则表达式, C++98只能用第三方的, 所以待会再折腾.
利用子表达式, 或运算我们可以写出以下pattern:
'<skin((\s*)|(name="(.*?)")|(src="(.*?)")|(subwidth="(.*?)")|(top="(.*?)")|(left="(.*?)"))*?>.*?</skin>'
不管双引号里面的是什么, 都提取出来. 然后应re.findall, 得出的匹配是一个元组, 依次是上面正则表达式中的子表达式, 第一个就是字符串最后一个匹配 ((\s*)|(name="(.*?)")|(src="(.*?)")|(subwidth="(.*?)")|(top="(.*?)")|(left="(.*?)"))
的子串, 比如空耳, left=”10”.
那么, test_bg
, test.bmp
, 0
, 10
, 10
的索引值应该分别是3,5,7,9,11. 于是我们可以这么提取:
# -*- coding: utf-8 -*- import re xml ='' pattern = r'<skin((\s*)|(name="(.*?)")|(src="(.*?)")|(subwidth="(.*?)")|(top="(.*?)")|(left="(.*?)"))*?>.*?</skin>' r = re.findall(pattern,xml) for i in r: print('name=%s'%i[3]) print('src=%s'%i[5]) print('subwidth=%s'%i[7]) print('top=%s'%i[9]) print('left=%s'%i[11])
能工作, 不过, 我们还可以对双引号内的内容格式做出一些限制, 或者等号附近不限空耳什么的, 结果如下:
# -*- coding: utf-8 -*- import re xml ='' pattern = r'<skin((\s*)|(name\s*=\s*"([^"]*?)")|(src\s*=\s*"([^"]*?)")|(subwidth\s*=\s*"([0-9]*?)")|(top\s*=\s*"([0-9]*?)")|(left\s*=\s*"([0-9]*?)"))*?>.*?</skin>' r = re.findall(pattern,xml) for i in r: print('name=%s'%i[3]) print('src=%s'%i[5]) print('subwidth=%s'%i[7]) print('top=%s'%i[9]) print('left=%s'%i[11])
但是, 我能否判断xml是否符合格式呢, 我觉得是做不到一步到位的, 如果是我, 先findall, 然后看看有没有缺什么属性, 没缺就算过了.
boost::regex
python试完了就该按照正题用C++实现了, 现在我们需要一个正则表达式库, 相信无论上哪问C++的正则表达式库, 十有八九都会回答boost的正则表达式库, 既然听起来怎么牛, 那我们就用用看吧.
首先你需要一个boost…
代码:
#include <iostream> #include <string> #include <boost/regex.hpp> int main() { std::string xml = "<skin name = \"test_bg\" src = \"test.bmp\" left = \"10\" top = \"11\" subwidth = \"0\" ></skin>"; std::string pattern = "<skin((\\s*)|(name\\s*=\\s*\"([^\"]*?)\")|(src\\s*=\\s*\"([^\"]*?)\")|(subwidth\\s*=\\s*\"([0-9]*?)\")|(top\\s*=\\s*\"([0-9]*?)\")|(left\\s*=\\s*\"([0-9]*?)\"))*?>.*?</skin>"; boost::regex reg(pattern); boost::smatch match; bool r = boost::regex_match(xml, match, reg); if (true == r) { std::cout << "name=" << match[4] << std::endl << "src=" << match[6] << std::endl << "subwidth=" << match[8] << std::endl << "top=" << match[10] << std::endl << "left=" << match[12] << std::endl; } return 0; }
boost::regex的match略有不同, 整个字符串会作为match集的第一个子串, 所以对应提取出来的属性值下标都加1.
Reference
- [1] : 刚从校园招聘拿了份金山的c++面试题,我是渣渣,一道也不会~~~~_c++吧_百度贴吧
- [2] : ming81. (搬运工)Boost学习之正则表达式–regex