[转]使用正则表达式解决配置文件字符串替换的思路和例子
http://zengrong.net/post/1233.htm
正则表达式是非常强大的字符串处理工具,但由于晦涩难懂,唯有不断的学习和使用,才能积累经验。我使用正则表达式总是断断续续,所以水平也很初级。下面就记录这次的使用经验,备查。
下面的xml代码是一个游戏技能配置文件的简化版,其中的items是一个技能,item是该技能的一个级别的值。desc属性是该技能的介绍文本。由于介绍中包含对技能的效果的引用,而技能的效果在不同的技能级别中的值是不同的,因此这里使用定界符来标识可能会变动的值。
针对定界符,我制定的规则很简单,用花括号{}包含要替换的属性值即可,如{key},其中key就是属性名称。对于使用数组方式提供的属性值,则使用{key[n]}的方式来提供,其中n是数组的索引。
程序中要做的,就是在游戏中需要技能的介绍的时候,会根据技能的级别获取到相关的的值,然后查询desc中有哪些定界符,再根据定界符获取到item中的值,最后进行替换。
这个工作虽然并不复杂,但也不是indexof能够解决的,后面就是我使用正则表达式的处理思路。对于XML的解析,我使用E4X。
<skill> <items id="2121" name="魔能烧烬" targetSide="2" type="special1" element="2" desc="主动技能。使魔导师能够掌握魔法精密之处,从而对目标造成{effect[0]}点的火元素伤害,同时减少目标{effect[1]}%MP上限。"> <item lv="1" effect="[20,4]" targetNum="1" expended="600" cd="20000" /> <item lv="2" effect="[40,6]" targetNum="1" expended="640" cd="20000" /> </items> <items id="1203" name="无情杀戮" targetSide="2" type="phy" element="-1" desc="主动技能。没有一丝怜悯的连续两次猛击目标要害,对目标造成{effect}点的物理伤害。"> <item lv="1" effect="1114" targetNum="1" expended="50" cd="13000" /> <item lv="2" effect="1180" targetNum="1" expended="60" cd="13000" /> </items></skill>
public static function isArray($str:String):Boolean { $str = $str.replace(/\s/g, ''); var _reg:RegExp = /^\[(\d+,?)+\d+\]$/; return _reg.test($str); }
public static function toArray($str:String, $delimiter:String=','):Array{ $str = $str.replace(/\s/g, ''); $str = $str.replace(/[\[\]]/g, ''); var __arr:Array = $str.split($delimiter); for(var i:int=0; i<__arr.length; i++) __arr[i] = int(__arr[i]); return __arr;}
public function getSkillVO($id:String, $lv:String):Object{ var __itemxml:XML = _skill.items.(@id==$id).item.(@lv==$lv)[0]; var __vo:Object = {}; var __effect:String = __itemxml.@effect.toString(); if(isArray(__effect)) __vo.effect = toArray(__effect); else __vo.effect = int(__effect); return __vo;}
private function replaceDesc($str:String, $skillvo:Object):String{ //支持全局匹配的正则 var __globalReg:RegExp = /{(\w+)(\[(\d)\])?}/g; //用于匹配每个全局匹配结果的正则 var __itemReg:RegExp = /{(\w+)(\[(\d)\])?}/; //全局匹配的结果 var __globalMatch:Array = $str.match(__globalReg); //待替换的键名数组 var __keys:Array = []; //待替换的值数组 var __values:Array = []; var __itemMatch:Array = null; var __itemIsArray:Boolean = false; var __itemKey:String = ''; for each(var __str:String in __globalMatch) { __itemMatch = __str.match(__itemReg); /*按照正则表达式规则,__itemMatch应该是有4个元素的数组: 1 整个字符串,2 第一个括号(\w+)的内容,3 第二个括号(\[(\d)\])的内容,4 第三个括号(\d)的内容 因此,如果第4个元素为undefined,就说明在字符串中,没有数组的定界符*/ __itemIsArray = __itemMatch[3] != undefined; //第2个元素就是去掉了花括号和数组定界符(如果有)的字符串,也就是要$skillvo中的变量名 __itemKey = __itemMatch[1]; //第1个元素是整个大字符串中的要被替换的部分,包含花括号 __keys.push(__itemMatch[0]); //如果值是数组中的元素,就是用数组中对应索引的值 if(__itemIsArray) __values.push($skillvo[__itemKey][__itemMatch[3]]); //否则,就直接使用变量的值 else __values.push($skillvo[__itemKey]); } //开始替换 for(var j:int=0; j<__keys.length; j++) { $str = $str.replace(__keys[j], __values[j]); } return $str;}