维生素C.net
Talents come from diligence, and knowledge is gained by accumulation 天才源于勤奋,知识源于积累。
难忘的1654天
博客园  首页  新随笔  新文章  联系  管理  订阅 订阅
随笔- 220  文章- 1  评论- 1659 
利用数学方法来大大降低一个逻辑判断实现的难度的例子
这是我的毕业设计(一个名叫viBlogging的blog系统)中需要的一个功能:在用户注册时根据输入的密码来显示密码强度(模仿passport的,不过是使用Atlas)。
对于密码强度,分为弱、中、强三等级,我的判断规则是:

1。如果密码的位数在3~4位之间,如果只含有字母,那么强度为弱。
2。如果密码的位数在3~4位之间,,如果还含有数字,那么强度也为弱。
3。如果密码的位数在3~4位之间,如果含有非字母数字的字符,那么强度为中。
4。如果密码位数在5~7之间,只含有字母的强度为弱
5。如果密码位数在5~7之间,同时还有数字的强度为中。
6。如果密码位数在5~7之间,同时还有非字母数字字符的强度为强。
7。如果密码长度大于7,如果只含有字母,那么强度为中。
8。如果密码长度大于7,如果还含有数字的话强度为中。
9。如果密码长度大于7,如果含有非字母数字字符的话,强度为强。

如果此时昨晚规则的分析后就着手写代码的话,那要写一堆if嵌套了。这样做的话,很可能会使得逻辑陷入混乱,很有可能一些情况就被忽略过去了。更为严重的是,这样写严重降低了代码的可读性。如果我必须用这样的方式来写,那我首先会去写unit test,其次再附详细的doc或注释来说明。

Okay,那我们进一步来分析一下。我们上述的9个条件都是由密码长度和密码复杂度两部分来结合判断出来的。那么我们可以拆分一下,如下图所示(请大家先只看第一个表格):(我点"insert image from gallery"后显示访问的资源不存在,无法从博客园这插入图片了,所以在首页可能看不到有图片)

o_viblogging password strength checking rule.PNG

我们现在写两个函数,分别计算长度和复杂度对应的强度,并返回。这里我们用{0,1,2}和{0,1,3}来表示(为什么后者是{0,1,3}在后面会讲到)那么我们可以很容易把上面的9个规则总结成第一个表格来表示。

到这里为止,我可以分别使用i和j来表示拆分后的强度的表示,好,现在我们可以去写清晰一点的if..else嵌套或if..switch嵌套了,这里我们可以用标识符了,采用了简单的分而治之的思想,整个规则也被简化为了7步了(读者可以自己考虑一下),思路清晰了许多。

但是目前为止,我们还是没有脱离嵌套条件分支语句的尴尬和不便。

Okay,我们继续对这个逻辑的返回结果作分析:
强度:情况1,情况2 = {(i1,j1),(i2,j2),....} § [(i+j)min,(i+j)max]

Strong: F,I = {(!0,3)} § [4,5]
Medium: G,E,H,C = {(2,0),(!0,1),(3,0)} § [2,3]
Weak: A,B,D = {(0,!3),(1,0)} § [0,1]

好,这样结果就很清楚了,当返回的i+j在>3时,那么强度肯定是strong的,如果小于2,那么肯定是weak的,剩下的就是Medium的了。这样只要写一个switch就完成任务了(我只在有双分支的时候用if,2个以上的都用switch,学过编译原理的应该知道它比if效率高,可是.net中他俩有什么性能区别我不知道,但是如果不出意外,应该还是比if效率高吧)。

此文仅在提供一种分解问题和归类问题各部分结果的小方法,当然也有“运气成分”(这就是为什么用{0,1,3}不用{0,1,2}的原因)。抛砖引玉,希望能学到更好的解决办法。
0
0
0
(请您对文章做出评价)
« 上一篇:无法登陆Hotmail/MSN Spaces的办法
» 下一篇:妈,母亲节快乐
posted on 2006-05-13 01:40 维生素C.NET 阅读(3619) 评论(28)  编辑 收藏 网摘 所属分类: ASP.NET

发表评论
468216
  回复  引用    
2006-05-13 09:06 | Echo.chen[未注册用户]
为什么不用正则表达式呢?
  回复  引用  查看    
2006-05-13 10:06 | 极地银狐.NET      
1,得到长度
2,依次匹配三个正则
3,根据业务逻辑付值并返回.

  回复  引用  查看    
2006-05-13 12:32 | 维生素C.NET      
@Echo.chen
@极地银狐.NET
使用正则表达式也是要写一定的逻辑判断的.此文的方法仅在利用简单的分治思想来细分逻辑,减少分支语句的使用.

  回复  引用    
2006-05-13 13:15 | 榛樼煶[未注册用户]
弱:l=".{3,4}" 中:m="这里先不写了" 高:h
string [] arrSExep = {h,m,l}
string [] arrValue = {"高","中","低"}
for(int i=0; i<arrSExep.length; i++)
{
if(Exp.Match(password,arrSExep[i]))
return arrValue[i];
}
大致写法应该如此
当然数组可以写一个二维的

  回复  引用  查看    
2006-05-13 13:59 | 阮      
嗯,思路不错

但是我还是回几句,遇到这样的问题,就想用if套,这就是错误的,我把我的想法写下吧。
string GetLevel(string password)
{
Hashtable levelMapping = new Hashtable();
Regex regex1 = new("略了");
levelMapp.Add(regex1, "弱");
.
.
.
Regex regex9 = new("略了");
levelMapp.Add(regex9, "强");

foreach (Regex regex in levelMapping.Keys)
{
if (regEx.IsMatch(password)) return levelMapping[regex];
}
}


  回复  引用  查看    
2006-05-13 14:30 | Anders Liu (lover_P)      
用查表的方法,很好!其实表的概念是计算机技术里很重要的一种思想,表的概念易于优化,代码精炼,如果优化的好,可以做到空间复杂度和时间复杂度都很低。不过就是难于编写文档和维护,如果没有好的文档,别人维护起来会比较痛苦,尤其是经过优化的。
  回复  引用  查看    
2006-05-13 16:27 | 小适(Greg)      
嗯~学习。
有时候换种思维模式来思考同一个问题,会得到完全不同的解决方案。

  回复  引用  查看    
2006-05-13 17:08 | THIN      
我倒是觉得计算密码的每个字符的编码值所在的范围再逐字加上相应的权重,这样的话,算法很简单,而且也更符合实际的问题逻辑 
  回复  引用  查看    
2006-05-13 17:19 | THIN      
32~47,58~64,91~96 为符号
65~90,97~122为字母
48~57为数字
分别加不同的权重,最后的结果值决定级别,再加上有2种+10的权重,有3种加20的权重之类的

  回复  引用  查看    
2006-05-13 18:08 | 萧寒      
我直接拷贝msn 或google的..
  回复  引用  查看    
2006-05-13 18:52 | 维生素C.NET      
@榛樼煶
string [] arrSExep = {h,m,l}
这个的逻辑怎么判断呢?

@阮
这样做的话似乎扩充性就不太高了

  回复  引用  查看    
2006-05-13 18:58 | 维生素C.NET      
@Anders Liu (lover_P)
博哥说的是,就像这个逻辑,如果不深入去看去分析的话,但看列出的逻辑虽能明白,但是如果做扩充还是很有你难度的,是不太好理解.谢谢博哥指点:-)

  回复  引用  查看    
2006-05-13 19:00 | 维生素C.NET      
@THIN
Thin哥,由于水平问题,看不太明白您的意思,可否给个简单的代码实现?

  回复  引用    
2006-05-13 21:11 | my.net[未注册用户]
THIN 的方法最好
  回复  引用  查看    
2006-05-13 21:46 | Dflying Chen      
@维生素C.NET
我简单解释一下:
首先将问题简化一下:密码只允许26个小写字母和10个数字,假设只有字母为弱,二者都有为强。(同时密码长度不会超过100位)

int sum = 0;
foreach(char c in password char array){
if (c is english char){
sum += 1;
}
else if(c is digital){
sum += 100;
}
}
if sum < 100 return week;
if sum > 100 return strong;

上述算法只需要O(n)的复杂度,是最快的。

但是考虑到复杂情况,为每种情况指定合适的权值不会很容易,甚至有时是不可能的,特别是有复杂逻辑的情况下。

  回复  引用  查看    
2006-05-13 22:43 | 维生素C.NET      
@Dflying Chen
那我返回的{0,1,3}这样的算不算权值呢?

  回复  引用  查看    
2006-05-14 03:57 | 寒枫天伤      
采用阀来控制判断,思路很不错。


  回复  引用  查看    
2006-05-14 10:47 | THIN      
之所以我会提出这样的算法,是我一贯认为程序应首先反映现实逻辑,在看待一个密码是否强时,人们一般会把密码从头到尾看一遍,看看只否有多种组成,看看是否够长,所以我会提出从头到尾检查整个密码,得出最后的强度指数的算法,下面的算法我最终没有用这种步骤是因为在考虑了人的思维逻辑之后要迁就机器思维,这样写也许代码比较简洁,一点不成熟的想法,希望对你有帮助,:),考虑到用C#写更简单,我就用JS实现了,代码如下。
<script type="text/javascript">
var PasswordStrength ={
HightLevel : 30,//强
MidLevel : 20,//中
LowLevel : 0,//弱
Factor : [1,2,5],//字符加数,分别为字母,数字,其它
KindFactor : [0,0,10,20],//密码含几种组成的加数
Regex : [/[a-zA-Z]/g,/\d/g,/[^a-zA-Z0-9]/g] //字符正则数字正则其它正则
}
PasswordStrength.StrengthValue = function(pwd)
{
var strengthValue = 0;
var ComposedKind = 0;
for(var i = 0 ; i < this.Regex.length;i++)
{
var chars = pwd.match(this.Regex[i]);
if(chars != null)
{
strengthValue += chars.length * this.Factor[i];
ComposedKind ++;
}
}
strengthValue += this.KindFactor[ComposedKind];
return strengthValue;
}
PasswordStrength.StrengthLevel = function(pwd)
{
var value = this.StrengthValue(pwd);
if( value >= this.HightLevel)
return "高,实在是高";
if( value >= this.MidLevel)
return "还行啦";
else
return "靠,这样也行";
}

alert(PasswordStrength.StrengthLevel("23"));
alert(PasswordStrength.StrengthLevel("abcd123"));
alert(PasswordStrength.StrengthLevel("abcd!%23"));
</script>
另外,"希望可以认识您,多像您学习.",学习不敢当的,我的MSN是thin37421@hotmail.com

  回复  引用  查看    
2006-05-14 11:02 | THIN      
为了灵活支持强度等级,还可以重构一下:
<script type="text/javascript">
var PasswordStrength ={
Level : ["高,实在是高","还行啦","靠,这样也行"],
LevelValue : [30,20,0],//强度值
Factor : [1,2,5],//字符加数,分别为字母,数字,其它
KindFactor : [0,0,10,20],//密码含几种组成的加数
Regex : [/[a-zA-Z]/g,/\d/g,/[^a-zA-Z0-9]/g] //字符正则数字正则其它正则
}
PasswordStrength.StrengthValue = function(pwd)
{
var strengthValue = 0;
var ComposedKind = 0;
for(var i = 0 ; i < this.Regex.length;i++)
{
var chars = pwd.match(this.Regex[i]);
if(chars != null)
{
strengthValue += chars.length * this.Factor[i];
ComposedKind ++;
}
}
strengthValue += this.KindFactor[ComposedKind];
return strengthValue;
}
PasswordStrength.StrengthLevel = function(pwd)
{
var value = this.StrengthValue(pwd);
for(var i = 0 ; i < this.LevelValue.length ; i ++)
{
if(value >= this.LevelValue[i] )
return this.Level[i];
}
}

alert(PasswordStrength.StrengthLevel("23"));
alert(PasswordStrength.StrengthLevel("abcd123"));
alert(PasswordStrength.StrengthLevel("abcd!%23"));
</script>

  回复  引用  查看    
2006-05-14 13:11 | dragonpig      
关于搂主“运气成分(这就是为什么用{0,1,3}不用{0,1,2}的原因)”的说法我不太同意。根据本问题的需求完全可以推导出{0,1,3}。其实{0,1,x}x>2都是可以的。
  回复  引用  查看    
2006-05-14 17:59 | 维生素C.NET      
@dragonpig
一开始我的想法很自然的就是对密码长度和密码复杂度的判断返回的都是{0,1,2}后来在总结规律的时候发现把对密码复杂度的返回改为{0,1,3}后可以直接通过加运算给三种强度“划清界限”。
您是如何推到出这个返回值的呢?请教一下判断的思路。

  回复  引用  查看    
2006-05-15 16:38 | 维生素C.NET      
@THIN
谢谢Thin.我昨天实现了一下遇到了点问题,不熟悉正则表达式.今天继续完善一下.
不过有一个地方,就是特殊字符我认为范围应该是在33-47,58-64,91-96,123-126之间.
程序的复杂度判断O()应该是程序中个部分的最高复杂度,很失败的是这个地方我给忘了...

  回复  引用  查看    
2006-05-15 16:51 | 最笨的那个      
可以这么实现
数字系数为8
字母系数为11
其他符号系数为25

比如密码为:
123 安全系数为24
abcd 安全系数为44
12@3 安全系数为49
123566 安全系数为48
a3#3b6 安全系数为72

然后根据0-(低)-45-(中)-75(高)划分

  回复  引用  查看    
2006-05-15 17:46 | THIN      
我把实现代码贴在了:http://thinhunan.cnblogs.com/archive/2006/05/14/399656.aspx
有了好的思路通知一声,呵呵

  回复  引用  查看    
2006-05-15 21:19 | 维生素C.NET      
@最笨的那个
您这样的思路我认为是不正确的。8位数字组成的密码其实是不安全的(用MD5对照表来穷举破解也不用太多时间),那么这样看来它的安全度应该是8*8=64>45=中,而如果是a&1~这个密码的话系数为69<75=中。但是后者的密码强度远远比前者要高。
也就是说,这个系数一定要经过数学推理出来才可以,如果只是任取,那么我认为这套规则是盲目的。

  回复  引用  查看    
2006-05-15 21:31 | 维生素C.NET      
@THIN
非常感谢!!

  回复  引用    
2006-07-25 15:54 | 路过的[未注册用户]
@最笨的那个

其实这想法不错,就是系数值得商榷
考虑到穷举破解时若每一位要尝试n个值,总共k位,就一共有n^k种情况,那么我们可以让每一位的权值为log(n),这样权值之和就表示了密码的难度
数字:log(10) = 1
字母:log(52) = 1.716
字母和数字:log(62) = 1.792
纯符号:log(29) = 1.462
字母、数字、符号:log(91) = 1.959

  回复  引用  查看    
2006-08-04 23:43 | xinGang      
考虑的很好,简化了程序代码;
只是应该考虑大写字母

注册用户登录后才能发表评论,请 登录 或 注册 。
IT新闻:
· 知名扩展 Firebug 的简化版登陆 Chrome
· Google 悄悄地启用 1e100.net,打枪地不要
· 从 Google 代码库找到的好东西
· 苹果在线商店临时关闭 或将推新Macbook
· 豆瓣网推出豆瓣电台iPhone客户端
每天10分钟,轻松学英语
专题:iPad  jQuery  Windows 7
网站导航:
博客园首页  IT新闻  个人主页  闪存  程序员招聘  社区  博问  网摘

China-pub 计算机图书网上专卖店!6.5万品种2-8折!
China-Pub 计算机绝版图书按需印刷服务

相关搜索:
ASP.NET

在知识库中查看:
利用数学方法来大大降低一个逻辑判断实现的难度的例子



公告

view my mvp profile 看看有多少人来访问我的Blog了!
hotmail

我的主页  个人资料
我的闪存  发短消息
<2006年5月>
日一二三四五六
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

搜索

 

常用链接

  • 我的随笔
  • 我的空间
  • 我的短信
  • 我的评论
  • 更多链接
  • 我的参与
  • 我的新闻
  • 最新评论
  • 我的标签

我参与的团队

  • .NET新手training活动(0/0)
  • 北京.NET俱乐部(0/0)
  • 烟台.NET俱乐部(0/0)
  • ASP.NET AJAX (Atlas)学习(0/0)
  • MVP(微软最有价值专家)团队(0/0)
  • 博客园培训团队(0/0)
  • Silverlight学习与研究(0/0)
  • CLR基础研究团队(0/0)

随笔分类(148)

  • ASP.NET(26)
  • Code Warehouse(20)
  • IronRuby,DLR(2)
  • LINQ(3)
  • Reading(3)
  • Training@cnblogs(23)
  • Ubuntu(4)
  • Windows Live(6)
  • Windows Mobile(7)
  • XHTML & Web Standard(54)

随笔档案(220)

  • 2008年3月 (2)
  • 2008年1月 (3)
  • 2007年12月 (3)
  • 2007年9月 (1)
  • 2007年8月 (2)
  • 2007年7月 (3)
  • 2007年6月 (3)
  • 2007年3月 (4)
  • 2007年2月 (3)
  • 2007年1月 (1)
  • 2006年12月 (1)
  • 2006年11月 (8)
  • 2006年10月 (6)
  • 2006年9月 (11)
  • 2006年8月 (5)
  • 2006年7月 (4)
  • 2006年6月 (1)
  • 2006年5月 (10)
  • 2006年4月 (8)
  • 2006年2月 (2)
  • 2006年1月 (1)
  • 2005年12月 (11)
  • 2005年11月 (13)
  • 2005年10月 (3)
  • 2005年9月 (1)
  • 2005年8月 (4)
  • 2005年7月 (3)
  • 2005年6月 (4)
  • 2005年4月 (5)
  • 2005年3月 (10)
  • 2005年2月 (7)
  • 2005年1月 (28)
  • 2004年12月 (15)
  • 2004年11月 (10)
  • 2004年10月 (5)
  • 2004年9月 (1)
  • 2004年6月 (13)
  • 2004年5月 (5)

文章档案(1)

  • 2005年5月 (1)

相册

  • ASPNET2tutorial
  • BlogUsing
  • My love and my friends
  • newGallery
  • 下一代网络图片

.net网站收藏

  • ASP.NET2.0 Tutorial
  • CodeBetter.com
  • F#
  • IIS.net
  • MS NewsGroup
  • NewsGroups
  • OnlyVC.org
  • VWD2005GuidedTour
  • ZDNet China软件技术专区

OSS 2007

  • Charsh
  • Kaneboy
  • Official Team Blog

Python

  • BeginnersGuide

好友的BLOG

  • DemoFox@JoyCode
  • DflyingChen
  • dudu
  • EricLee
  • hbifts
  • idior
  • Jesee Qing
  • Lion
  • Rickie
  • Samuel
  • Steph`s Website
  • 翱翔.Net
  • 陈敬熙
  • 发条木偶
  • 葛涵涛
  • 古道风
  • 寒枫天伤
  • 老猫の理想
  • 刘老师
  • 刘彦博
  • 吕震宇
  • 木野狐
  • 佘广
  • 王sir
  • 小涛
  • 小新
  • 肖老师
  • 旋哥

积分与排名

  • 积分 - 426433
  • 排名 - 100

最新评论

  • 1. Re:http的基础知识帮助减少代码量和复杂度的一个Demo
  • 不知道说的啥
  • --YJJ
  • 2. re: 结构体,值类型和接口
  • <a title="不锈钢无缝管" href=" <a title="304不锈钢管价格" href=" <a tit...
  • --站
  • 3. re: 结构体,值类型和接口
  • <a href=" target="_blank">不锈钢管</a> <a href=" target="_blank...
  • --无缝不锈钢管
  • 4. re: 结构体,值类型和接口
  • <a href=" <a href=" ...
  • --无缝不锈钢管
  • 5. re: 结构体,值类型和接口
  • <a href=" target="_blank">不锈钢管</a> <a href=" target="_blank...
  • --无缝不锈钢管

阅读排行榜

  • 1. 英文名字及含义(29568)
  • 2. SQL Server 2005 Remote Access(16120)
  • 3. Visual Studio 2005 Team Edition和SQL Server 2005的下载(15310)
  • 4. ASP.NET SESSION的使用及原理(14805)
  • 5. Windows Installer 3.1(11793)

评论排行榜

  • 1. .NET Beginner Training Step by Step开始启动(320)
  • 2. Windows Live Messenger 8.0 Beta 的邀请(100)
  • 3. 加入[ 下一代网络web技术(Next Generation Web Application)团队Blog ](93)
  • 4. 博客园新手.net技术培训活动(55)
  • 5. 为什么在vista上做开发?(54)
Copyright ©2010 维生素C.NET