最近在工作中需要在应用中外接蓝牙打印设备,实现打印功能。大体流程就是把app中的数据进行解析,处理成打印机的一系列指令。我们采用自定义标签实现了该功能。例如<dk-prt-text style = "center;">cdcd</dk-prt-text>就代表打印居中文字cdcd。<dk-prt-img src="xx" style="center"/>就是打印一个居中的图片。打印过程的难点就是在处理标签的过程。
由于打印的过程不外乎分为打印文字和打印标签,所以可以采取递归的方式进行处理问题,递归结束的标志为内容字符串的长度为0;代码如下:
- (void)parseContent:(NSString *)content command:(Command *)command {
//先判断可以直接打印的内容,即直接打印文字
NSRange rangeOfTagStart = [content rangeOfString:@"<"]
if (rangeOfTagStart.location != NSNotFound && rangeOfTagStart.location) {
//直接在command中添加打印内容,代码忽略
content = [content substringFromIndex:rangeOfTagStart.location];
}else {
//没有找到标签,则说明都是直接打印的文字,则直接进行打印,并设置content = @“”
return;
}
NSRange rangeOfTagEnd = [content rangeOfString @">"];
NSString *tagString = @"";
if (rangeOfTagEnd.location != NSNotFound) {
//如果存在, 则获取标签字符串,并对tagString赋值
}else {
//如果不存在,则直接输出content
return;
}
//1. 对tagString进行格式合法性判断,如果格式合法,则进行下一步,如果格式不合法,则直接输出tagString, 然后递归调用方法,进行下一步处理。
//2. 获取tagString中的style属性值,写入打印命令中
//3. 分别对不同的标签进行处理
//4. 判断content是否为空,如果为空则发送command到打印机,如果不为空,则进行递归处理
}
有些关键的点需要特别注意
-
如何判断标签的合法性
对于单个标签,例如
<dk-prt-img src="xx" style="center"/>
,直接使用正则表达式<dk-prt-img\\s+ src\\s*=\\s*\"[ ^\"]*\"\\s*>
就可以搞定了。对于需要配对的标签,例如<dk-prt-text style = "center;">cdcd</dk-prt-text>
,则处理的时候,遇到<dk-prt-text style = "center;">
你就需要判断有没有和它配对的</dk-prt-text>
标签,相应的,遇到</dk-prt-text>
标签的时候,你也需要进行判断。对于起始标签
<dk-prt-text>
, 我想到了类似堆栈的方式,设置了一个整型变量count,初始值为1。采用递归的方式,遍历该标签之后的字符串,遇到起始标签,则count+1,遇到结束标签,则count-1,当count为0的时候,结束递归,说明找到与之相匹配的结束标签。如果遍历结束,count的值不为0,则说明没有找到,直接输出这个起始标签。
对于结束标签的处理<\dk-prt-text>
的处理,起始相对来说更简单,也是使用一个整型变量进行计数,打印一个起始便签的时候+1,打印一个结束标签的时候-1, 打印结束标签的时候,先判断变量是否为0,如果为0,说明前面没有与之配对的起始标签,则直接输出结束标签的文本。
-
标签内属性的处理。
对于标签内style属性的处理,要思考两个东西,一个是如何获取style中的值,另外一个是style属性的作用范围处理。
style值的处理,可以简单的使用正则表达式进行处理,style属性的作用范围,对于img这种单个标签来说,打印完图片就直接结束了,然后我们直接在打印命令中输入恢复默认样式的指令即可。但是对于text这种有开始和结束的标签,我们要思考标签嵌套的可能,例如<dk-prt-text style="small">hdcd<dk-prt-text>CDCD</dk-prt-text></dk-prt-text>
,我的想法是创建一个可变数组,遇到一个<dk-prt-text>
,则保存这个标签中的style属性值,为空也进行保存。遇到一个\<dk-prt-text>
则删除数组中的最后一个元素,使用倒二个属性值进行设置处理。如果删除最后一个元素后,数组为空,则使用默认的属性值进行设置。