- 浏览: 632409 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
liuche20083736:
非常好
从问题看本质: 研究TCP close_wait的内幕 -
xiaopohai85707:
优化算法与原来需求不符
过滤字符的性能调优?挤一挤还是有的 -
kmy_白衣:
生成的area图有时候 标签的数值和图标上看上去的数值不一致。 ...
OpenFlashChart2之恶心文档 -
tom&jerry:
大神,请教一个问题,按名称排序为何无效,用的2.4.3 XPA ...
深入浅出jackrabbit之十三 查询之AST和QT -
jd2bs:
改成精确匹配可以了< filter-mapping &g ...
细谈Ehcache页面缓存的使用
/*
*author: ahuaxuan(张荣华)
*date: 2010-05-28
*/
起因
前一段时间和其他系统集成, 另外一个系统对某个参数有一个限制,需要将字符串中的特殊字符过滤掉, 由于需要过滤的字符是对方定义的, 所以对方直接把他们系统中的过滤的代码给我了, 代码如下:
private String escape(String s) { if (s == null) { return null; } StringBuilder sb = new StringBuilder(s.length()); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c == '\\' || c == '+' || c == '-' || c == '!' || c == '(' || c == ')' || c == '^' || c == '[' || c == ']' || c == ':' || c == '{' || c == '}' || c == '~' || c == '*' || c == '?' || c == '|' || c == '&' || c == '>' || c == '<') { sb.append(“ ”); } else { sb.append(c); } } return sb.toString(); }
拿到代码之后, ahuaxuan没有作过多的思考, 而是直接把这段代码贴到自己的代码中, 事实证明它运行”良好”.今天重新审视这段代码的时候,发现还是有改进的余地.
分析
特征分析, 上面这段代码的主要作用是将字符串中出现的固定字符替换成空格, 这些需要替换的字符也是我们常见的字符.
面对这样一个需求, 有的程序员会想到replace方法,有的程序员会想到上面的多次||的方法(但是多次||的问题在于如果你的字符不是需要过滤的字符,那么程序就一直会执行到最后一个||,这绝对性能上的浪费阿), 也有的程序员会想到hash的方式. 其实我们的最终目的其实就是:
给定一个字符, 你怎么判断这个字符是否在某个常见的字符列表中.
你肯定不想用迭代, 你也肯定不想用if else if, 你可能比较喜欢用hash, 但是注意这里的”常见字符”这几个字.
是因为它们在ascii 码里所以它们才常见, 还是因为他们常见,所以放到ascii 码里呢, 但不管怎么样, 事实上它们确实是在ascii码里, 也就是说他们之中最大的都不会超过255.
所以这个时候, 我们的方案就浮出水面了, 由于我们只要检查每个char是否==这些常见的char就行了. 说到这里, 你是不是又想起了if else if, 这个只是思维的惯性, 如果你再把这些char想像成一个个数字呢.
本质和方案
于是需求就转换成了---在个数字段中, 找到某些我们预先定义的需要过滤的数字, 并将起替换成空格,而我们定义的数字都是小于255的.
在这样一个需求中, 最快的方式是啥咧, 数组是不, 比如说我们定义的需要过滤的数字是[2, 5], 我们的数字序列是1 2 3 4 5 10 11 110......
那么我们只要遍历这个数字, 然后判断这个数字在我们的过滤数组中是否存在. 我们的过滤数组怎么组织呢?
filterchars = [0, 0, 1, 0, 0, 1],
然后我们只需要判断filterchars[k] > 1就知道是个字符是否是需要过滤的字符了(当然这里要注意数组越界了).
public int[] dic = new int[256]; private String filterChars = "\\+-!()^[]:{}~*?|&><"; /** * User: ahuaxuan * Date: 2010-5-28 * Time: 13:17:11 */ public CharFilter() { for (int k = 0; k < filterChars.length(); k++) { //这里浪费了一些byte. char c = filterChars.charAt(k); if (c < 256) { dic[c] = 1; } } } public String newEscape(String abc) { if (abc == null) { return null; } StringBuilder rs = new StringBuilder(abc.length()); for (int k = 0; k < abc.length(); k++) { char c = abc.charAt(k); if (c < 256 && dic[c] > 0) { rs.append(" "); } else { rs.append(c); } } return rs.toString(); }
测试报告
下面我们来看看这段代码:
相同功能的两段代码, 运行一下测试, 测试方法如下:
/** * User: ahuaxuan * Date: 2010-5-28 * Time: 13:17:11 */ public static void main(String [] args) { for (int n = 0; n < 10; n++) { System.out.println("------------------------" + n); StringBuilder txt = new StringBuilder(1000); for (int k = 0; k < 100; k++) { txt.append(UUID.randomUUID().toString()); } CharFilter pt = new CharFilter(); String abc = txt.toString(); long begin = System.currentTimeMillis(); for (int k = 0; k < 10000; k++) { pt.escape(abc); } System.out.println("escape : " + (System.currentTimeMillis() - begin) + "ms"); begin = System.currentTimeMillis(); for (int k = 0; k < 10000; k++) { pt.newEscape(abc); } System.out.println("new escape : " + (System.currentTimeMillis() - begin) + "ms"); } }
不到1k的一个文本, 每种方法调用100次, 最终得到的结果是:
escape : 103ms
new escape : 67ms
------------------------1
escape : 60ms
new escape : 42ms
------------------------2
escape : 61ms
new escape : 48ms
------------------------3
escape : 58ms
new escape : 39ms
------------------------4
escape : 56ms
new escape : 39ms
------------------------5
escape : 80ms
new escape : 39ms
------------------------6
escape : 55ms
new escape : 40ms
------------------------7
escape : 55ms
new escape : 38ms
------------------------8
escape : 55ms
new escape : 38ms
------------------------9
escape : 59ms
new escape : 41ms
如果我们把对每个不到1K的文本的过滤调用上升到10000次, 那么测试结果是:
escape : 627ms
new escape : 433ms
------------------------1
escape : 564ms
new escape : 390ms
------------------------2
escape : 624ms
new escape : 390ms
------------------------3
escape : 561ms
new escape : 385ms
------------------------4
escape : 564ms
new escape : 388ms
------------------------5
escape : 600ms
new escape : 391ms
------------------------6
escape : 559ms
new escape : 382ms
------------------------7
escape : 564ms
new escape : 394ms
------------------------8
escape : 573ms
new escape : 395ms
------------------------9
escape : 566ms
new escape : 406ms
文体大小和过滤次数上升之后, 优化之后的方法比原先的方法快了近200ms.
总结:
性能就像女人的胸, 挤一挤还是有的.
当然如果你觉得文中的手段是太入门级了, 那你可以看看ahuaxuan的这篇文章:
评论
发表评论
-
Master-Slave,Spring,Hibernate,故事曲折离奇,情结跌宕起伏
2009-02-05 13:49 8576/** *作者:张荣华 *日期 ... -
弃成见,反省,并重新认识struts.i18n.encoding
2008-12-24 15:42 3776[size=medium]之前和大家讨论了struts2.0中 ... -
关键字:查询,事务,粒度
2008-08-22 17:05 5028[size=medium]/** *作者: ... -
看看mina和memcached的联姻(适合不同语言客户端,高并发?)
2008-07-21 17:06 7881[size=medium]/** * 作者:张荣华 * 日 ... -
如何解决mysql的master-slave模式中ReplicationDriver的使用问题
2008-06-19 18:23 8164/** * 作者:张荣华 * 日期:2008-6-19 ... -
别装了,难道你们不想把properties直接注入到object中去(spring-plugin)?
2008-04-09 18:01 3582[size=small]/** *作者:张荣华(ahuaxu ... -
用jamon来监控你的sql执行效率
2008-02-25 15:48 3658/** *作者:张荣华 *日期:2008-2-25 ... -
java同msn的通信,大家想想用途吧
2007-11-24 17:14 2482程序员的生活真是单调,除了编程还是编程,工作日 ... -
EAI企业应用集成场景及解决方案
2007-09-21 18:21 3113/** *作者:张荣华(ahuaxuan) *2007-9 ... -
quartz和应用的集群问题
2007-08-21 18:36 12728之前看到很多关于quartz的讨论,尤其是关于quar ... -
优化程序之前,可用Jamon来监测你的Spring应用
2007-08-14 18:14 8005/** *作者:张荣华(ahuaxuan) *2007-8-1 ... -
请问责任链真的是一种设计模式吗
2007-07-26 18:12 9305坛子上讨论设计模式的也挺多的,但是关于这个责任链模式还没有人提 ... -
把ActiveMQ的控制台整合到你的web程序中
2007-07-19 12:06 8718在使用ActiveMQ的时候把ActiveMQ的控制台整 ... -
设计模式之:解剖观察者模式
2007-07-17 16:12 6809[size=9] 论坛上很多人都 ... -
java邮件:在简单和复杂之间的方案
2007-07-11 18:07 7547/** *作者:张荣华(ahuaxu ... -
强强连手, 在模板中分页,看Freemarker和displaytag的结合
2007-07-09 09:22 6877/** *作者:张荣华(ahuaxuan) *2007-0 ... -
解惑:在spring+hibernate中,只读事务是如何被优化的。
2007-06-28 18:22 7571/** *作者:张荣华(ahuaxuan) *2007- ... -
让webwork零配置 第二章(实现)(实例已放出,大家可以下载运行)
2007-06-25 09:23 5670/** *作者:张荣华(ahuaxuan) *2007-0 ... -
让webwork2零配置,第一章(主贴再次更新)
2007-06-18 15:41 13230/** *作者:张荣华(ahuaxuan) *2007-0 ... -
Spring声明式事务管理源码解读之事务提交
2007-06-11 09:19 7248/** *作者:张荣华(ahuaxuan) *2007-0 ...
相关推荐
字符过滤字符过滤 字符过滤字符过滤字符过滤字符过滤字符过滤字符过滤字符过滤字符过滤
《mysql管理之道:性能调优、高可用与监控》由资深mysql专家撰写,以最新的mysql版本为基础,以构建高性能mysql服务器为核心,从故障诊断、表设计、sql优化、性能参数调优、mydumper逻辑、xtrabackup热备份与恢复、...
什么是数据库?什么是关系数据库管理系统(RDBMS)? 什么是SQL?列举一些常见的SQL命令。...什么是数据库性能监控和调优工具?列举一些常用的工具。 什么是数据库连接字符串?它的格式和参数有哪些
一个php过滤非法字符类,参数检查并写日志,提交的参数非法,系统会记录您的本次操作,SQL注入日志
IIS 过滤字符 防火墙IIS 过滤字符 防火墙IIS 过滤字符 防火墙 基于IIS 可以自定义 是一个dll ,调用进去就可以了
过滤一个字符串中包含有表情的字符,例如一个用户昵称中包含的表情
MyEclipse6.0 制作的小样例。包含Java特定字符。标签过滤。字符编码转换。代码清晰易懂。方便使用,作为工具非常合适 使用 List 作为 过滤字符库
6.如何使用BIG5显示一个字符串?(Visual C++编程 源代码)6.如何使用BIG5显示一个字符串?(Visual C++编程 源代码)6.如何使用BIG5显示一个字符串?(Visual C++编程 源代码)6.如何使用BIG5显示一个字符串?...
labview8.6编写的将字符串过滤成指定的字符串,包括 数值,大写,小写,十进制,16进制,8进制等
17.如何从文本文件中读取一个字符串?(Visual C++编程 源代码)17.如何从文本文件中读取一个字符串?(Visual C++编程 源代码)17.如何从文本文件中读取一个字符串?(Visual C++编程 源代码)17.如何从文本文件中...
字符编码过滤器 j2ee字符字符编码 字符编码过滤器 字符编码转换 post字符转换
Java过滤字符串的方法,Java过滤字符串的方法,过滤敏感信息
3.如何旋转显示字符串?(Visual C++编程 源代码)3.如何旋转显示字符串?(Visual C++编程 源代码)3.如何旋转显示字符串?(Visual C++编程 源代码)3.如何旋转显示字符串?(Visual C++编程 源代码)3.如何旋转...
能够过滤字符串中图片及其他的一些标签
2.如何折行显示字符串?(Visual C++编程 源代码)2.如何折行显示字符串?(Visual C++编程 源代码)2.如何折行显示字符串?(Visual C++编程 源代码)2.如何折行显示字符串?(Visual C++编程 源代码)2.如何折行...
在android输入框中,经常会遇到用户输入奇奇怪怪的表情符号,在网上找了一圈。一般做法都是去匹配emoji字符。根本无法解决问题。换一个思路,只允许输入框中输入什么内容,具体见代码
4.如何显示星期月份字符串?(Visual C++编程 源代码)4.如何显示星期月份字符串?(Visual C++编程 源代码)4.如何显示星期月份字符串?(Visual C++编程 源代码)4.如何显示星期月份字符串?(Visual C++编程 源...
VB过滤中文字符串源码 VB过滤中文字符串源码 VB过滤中文字符串源码 VB过滤中文字符串源码 VB过滤中文字符串源码
本文主要通过一下几个方面介绍:使用SQLDMV查找慢速查询、通过APM解决方案查询报告、SQLServer扩展事件、SQLAzure查询性能洞察等相关内容。本文来自博客园,由火龙果软件Anna编辑、推荐。SQLServer的一个重要功能是...
private string FilterHTML(string contents) { string strTmp =string.Empty; strTmp = System.Text.RegularExpressions.Regex.Replace(contents, "<(.[^>]*)>", ""); return strTmp; }