|
主题: .NET中正则表达式应用一些体会
|
 蓝鲸
职务:版主
等级:5
金币:42.1
发贴:2614
注册:2001/12/20 15:57:57
|
#12004/8/30 11:28:03
前些想自己写个.net的论坛,却发现些问题,其中就是这UBBCODE,以前用ASP写的,只知引用,不是这代码意思。但现在ASP代码移到C#或VB中就有问题了,主要是不理解这正则表达式。这几天就好好研究了一下,只懂了些大概。 看了以后,才觉得这表达式真非常有用,特别是验正一些如日期,URL,Email或输入等,特别管用。 如日期格式:1980/12/18,12/18/1980,1980-12-18,1980年12月18,1980-2-8, 1980-02-08,一大堆格式,如果要验证,以前觉很困难,因为输入不要指望别人按你设想的格式输入,他们很可能会以其中之一的格式验证。其中还要考虑到他们的日期格式是错误的如1980-2-31等。用正则表达式就可解决了。 日期格式代码在家里,很快我会发上来,但觉代码有些多,有兴趣的朋友可以自制一个。
非常大鱼
|
 蓝鲸
职务:版主
等级:5
金币:42.1
发贴:2614
注册:2001/12/20 15:57:57
|
#22004/8/30 11:47:39
下面试了个例子,较简单,但需要了解一下正则表达式。 这里对表达式不想作教程了,VS.NET联机帮助已经非常好了。
如商品开票中有票号,格式很多,如SB0001890,123-890-899007,A01BB000898等,如果新票要在数字位上加1变成SB0001891,123-890-899008,A01BB000899,以前很可以会用法读取最后一位非数字位。用正则表达式,可以轻易把SB0001890分成"SB"和"0001890,接下去就省力了。
/// <summary> /// 使原来的编号的数字位加1 /// </summary> public string GetBillID(string strID) { string headStr; // 头字符串 string digitalStr; // 后位的数字字符串 string maxStr = ""; // 数字位的最大数字 string FormatStr = ""; // 格式化字符串 int newStr;
// 用正则函数去掉头字符串 digitalStr = Regex.Replace(strID, @"^\w*\D+", ""); // 取得头字符串 headStr = Regex.Replace(strID, @"\d*$", ""); // 如果后位没有数字,则返回空串 if (digitalStr == "") { return ""; }
// 取得最大数字和格式化字符串 for (int i = 1; i <= digitalStr.Length; i++) { maxStr += "9"; FormatStr += "0"; } // 如果数字字串和最大数字相同,则返回不能再加的字串 if (digitalStr == maxStr) { return "MAX"; }
// 取得格式化字符串 newStr = Convert.ToInt32(digitalStr) + 1; return headStr + newStr.ToString(FormatStr); }
解释一下 @"^\w*\D+": ^ 表示靠最前 \w 表示任何字符 * 表示0个以上该字符的重复出现 \D 表示非数字字符 + 表示1个以上该字符的重复出现
@"\d*$": \d 表示数字字符(注意与\D区别) * 表示0个以上该字符的重复出现 $ 必须靠未尾
非常大鱼
|
 蓝鲸
职务:版主
等级:5
金币:42.1
发贴:2614
注册:2001/12/20 15:57:57
|
#32004/8/30 16:37:30
/// <summary> /// 检验Email字符串格式是否正确 /// </summary> public bool IsEmailFormat(string strEmail) { return Regex.IsMatch(strEmail, @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"); }
是不是有些怕了, ;)但一定要有耐心,这代码已验证了,如果熟悉ASP,可以改一下的。 最近不太用ASP了,有些不常的用法有些忘了,所以就不写ASP的了,但如果语法熟悉一些的话,换一下不是问题,可参看UBBCode用法。
非常大鱼
|
 蓝鲸
职务:版主
等级:5
金币:42.1
发贴:2614
注册:2001/12/20 15:57:57
|
#42004/8/30 16:43:40
/// <summary> /// 检验日期格式是否正确 /// </summary> public string IsDateFormat(string strDate) { Regex r1 = new Regex(@"^(?<year>[1-9][0-9]{0,3})/(?<month>[0-9]{1,2})/(?<day>[0-9]{1,2})$"); Regex r2 = new Regex(@"^(?<year>[1-9][0-9]{0,3})-(?<month>[0-9]{1,2})-(?<day>[0-9]{1,2})$"); Regex r3 = new Regex(@"^(?<year>[1-9][0-9]{0,3})年(?<month>[0-9]{1,2})月(?<day>[0-9]{1,2})日$"); Regex r4 = new Regex(@"^(?<month>[0-9]{1,2})/(?<day>[0-9]{1,2})/(?<year>[1-9][0-9]{0,3})$");
// 取得日期的年,月,日 string year, month, date;
if(Regex.IsMatch(strDate,@"^(?<month>[0-9]{1,2})/(?<day>[0-9]{1,2})/(?<year>[1-9][0-9]{3})$")) { year = r4.Match(strDate).Result("${year}"); month = r4.Match(strDate).Result("${month}"); date = r4.Match(strDate).Result("${day}"); } else if (Regex.IsMatch(strDate,@"^(?<year>[1-9][0-9]{0,3})/(?<month>[0-9]{1,2})/(?<day>[0-9]{1,2})$")) { year = r1.Match(strDate).Result("${year}"); month = r1.Match(strDate).Result("${month}"); date = r1.Match(strDate).Result("${day}"); } else if(Regex.IsMatch(strDate,@"^(?<year>[1-9][0-9]{0,3})-(?<month>[0-9]{1,2})-(?<day>[0-9]{1,2})$")) { year = r2.Match(strDate).Result("${year}"); month = r2.Match(strDate).Result("${month}"); date = r2.Match(strDate).Result("${day}"); } else if(Regex.IsMatch(strDate,@"^(?<year>[1-9][0-9]{0,3})年(?<month>[0-9]{1,2})月(?<day>[0-9]{1,2})日$")) { year = r3.Match(strDate).Result("${year}"); month = r3.Match(strDate).Result("${month}"); date = r3.Match(strDate).Result("${day}"); } else { return "error"; }
// 最后检查日期的正确性 try { System.DateTime dt = new DateTime(Convert.ToInt32(year), Convert.ToInt32(month), Convert.ToInt32(date)); return dt.ToString("yyyy-MM-dd"); } catch { return "error"; } }
正则表达式,初看就让人生畏,只要坚持 :rolleyes: 另外还是觉本代码不是很完美,代码有些多,但一时也想不到好的方法。 最后一段new DateTime的方法,是.net固有的方法,尝试建立日期格式,如能建立,说明输入是正确的,不能就返回"ERROR"。 ;)当然,你也可以用自己方法去验证年份正确性,如2月29日是否正确等问题。但我是不会再去做这样的事了,别人已经做得很完美了,就省下这时间去做些更有意义的事了。
非常大鱼
|
 eShaka
职务:版主
等级:6
金币:15.0
发贴:5019
注册:2001/6/13 18:13:53
|
#52004/8/31 12:02:48
能介绍一些正则表达式的学习资料嘛,入门型的
|
 缺缺
职务:管理员
等级:8
金币:41.0
发贴:9620
注册:2004/1/14 19:14:47
|
#62004/8/31 13:06:57
刚在手绘版聆听楼主高论,没有想到又在这里看到这些代码.原来楼主兴趣如此之广泛,跳跃幅度如此之大.  to楼上:外人初见正则,往往茫然不知所云,其实只要稍稍明白了一点点,那么研究起来就容易多了.
|
 蓝鲸
职务:版主
等级:5
金币:42.1
发贴:2614
注册:2001/12/20 15:57:57
|
#72004/8/31 16:03:30
见笑了,几年前搞过些编程,现在要用到了,也是硬着头皮学。 正则函数在网上我下载过一些论文,比较易懂,但在全面性方面,VS.NET的联机帮助应该是最好的。搜索关键词可以是“正则表达式”,另对Regex类也应该了解。
我在网上的资料看看是不是有版权等问题,如果没有就转过来。
非常大鱼
|
 蓝鲸
职务:版主
等级:5
金币:42.1
发贴:2614
注册:2001/12/20 15:57:57
|
#82004/8/31 16:58:11
字符匹配 --------------------------------------------------------------------------------------- . 匹配任何字符 grep .ord sample.txt 匹配 “ford”, “lord”, “2ord” [ ] 匹配在方括内列出的任何字符 grep [cng]ord sample.txt 匹配 “cord”, “nord”, and “gord” [^ ] 匹配除了方括内字符以外的任何字符 grep [^cn]ord sample.txt 匹配 “lord”, “2ord”, 不匹配 “cord” or “nord”
例子: grep [a-zA-Z]ord sample.txt 匹配 “aord”, “bord”, “Aord”, “Bord” grep [^0-9]ord sample.txt 匹配 “Aord”, “aord”, etc. but not “2ord”
重复操作符 --------------------------------------------------------------------------------------- ? 指定零个或一个匹配;例如 \w? 或 (abc)?。等效于 {0,1}。 egrep ?erd sample.txt Will match “berd”, “herd”, etc. and “erd” * 指定零个或更多个匹配;例如 \w* 或 (abc)*。等效于 {0,}。 egrep n.*rd sample.txt Will match “nerd”, “nrd”, “neard”, etc. + 指定一个或多个匹配;例如 \w+ 或 (abc)+。等效于 {1,}。 egrep [n]+erd sample.txt Will match “nerd”, “nnerd”, etc., but not “erd” {n} 指定恰好 n 个匹配 egrep [a-z]{2}erd sample.txt Will match “cherd”, “blerd”, etc. but not “nerd”, “erd”, “buzzerd”, etc. {n,} 指定至少 n 个匹配 egrep .{2,}erd sample.txt Will match “cherd” and “buzzerd”, but not “nerd” {n,m} 指定至少 n 个但不多于 m 个匹配 egrep n[e]{1,2}rd sample.txt Will match “nerd” and “neerd”
锚 --------------------------------------------------------------------------------------- 锚是指它所要匹配的格式,如图C所示。使用它能方便你查找通用字符的合并。例如,我用vi行编辑器命令:s来代表substitute,这一命令的基本语法是: s/pattern_to_match/pattern_to_substitute/
^ 指定匹配必须出现在字符串的开头或行的开头 s/^/blah / Inserts “blah “ at the beginning of the line $ 指定匹配必须出现在以下位置:字符串结尾、字符串结尾的 \n 之前或行的结尾 s/$/ blah/ Inserts “ blah” at the end of the line \< Match at the beginning of a word s/\</blah/ Inserts “blah” at the beginning of the word egrep \<blah sample.txt Matches “blahfield”, etc. \> Match at the end of a word s/\>/blah/ Inserts “blah” at the end of the word egrep \>blah sample.txt Matches “soupblah”, etc. \b 指定匹配必须出现在 \w(字母数字)和 \W(非字母数字)字符之间的边界上。 匹配必须出现在单词边界上,即出现在由任何非字母数字字符分隔的单词中第一个或最后一个字符上。 egrep \bblah sample.txt Matches “blahcake” and “countblah” \B 指定匹配不得出现在 \b 边界上 egrep \Bblah sample.txt Matches “sublahper”, etc.
非常大鱼
|
 蓝鲸
职务:版主
等级:5
金币:42.1
发贴:2614
注册:2001/12/20 15:57:57
|
#92004/8/31 17:01:05
间隔 --------------------------------------------------------------------------------------- Res中的另一可便之处是间隔(或插入)符号。实际上,这一符号相当于一个OR语句并代表|符号。下面的语句返回文件sample.txt中的“nerd” 和 “merd”的句柄: egrep “(n|m)erd” sample.txt 间隔功能非常强大,特别是当你寻找文件不同拼写的时候,但你可以在下面的例子得到相同的结果: egrep “[nm]erd” sample.txt 当你使用间隔功能与Res的高级特性连接在一起时,它的真正用处更能体现出来。
一些保留字符 --------------------------------------------------------------------------------------- Res的最后一个最重要特性是保留字符(也称特定字符)。例如,如果你想要查找“ne*rd”和“ni*rd”的字符,格式匹配语句“n[ei]*rd”与“neeeeerd” 和 “nieieierd”相符合,但并不是你要查找的字符。因为‘*’(星号)是个保留字符,你必须用一个反斜线符号来替代它,即:“n[ei]\*rd”。其它的保留字符包括: · ^ (carat) · . (period) · [ (left bracket} · $ (dollar sign) · ( (left parenthesis) · ) (right parenthesis) · | (pipe) · * (asterisk) · + (plus symbol) · ? (question mark) · { (left curly bracket, or left brace) · \ backslash 一旦你把以上这些字符包括在你的字符搜索中,毫无疑问Res变得非常的难读。比如说以下的PHP中的eregi搜索引擎代码就很难读了。 eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*$",$sendto) 你可以看到,程序的意图很难把握。但如果你抛开保留字符,你常常会错误地理解代码的意思。
非常大鱼
|
 蓝鲸
职务:版主
等级:5
金币:42.1
发贴:2614
注册:2001/12/20 15:57:57
|
#102004/8/31 17:09:25
这是转帖,原文用表格排列的,这里看来有点不舒服,我想还是看帮助更好,网上可以搜索些例子。 正则表达式还有些高级应用,我也不是很理解,只是现在还暂时用不到,所以没忙着全部去理解。先消化一下,我就这样,不会等全部学会了才去写代码。写代码拙劣些没关系,只要坚持写。我也不会把一件事突然钻得很深,成了单个腿很大的人,要全面掌握了,在应用时去各个突破。
非常大鱼
|
 三仙半
职务:普通成员
等级:1
金币:0.0
发贴:241
注册:2006/1/24 15:46:21
|
#112006/7/4 18:28:35
能解释一下Regex是什么意思吗?另外,在ASP中如何应用正则表达式? 请鲸兄指教。
闭起眼睛看人生
|
 浮尘
职务:普通成员
等级:3
金币:7.0
发贴:1258
注册:2001/11/19 12:41:09
|
#122006/7/5 13:42:48
判断是否为日期,我觉得不使用正则更简单。
private bool IsDate(string strDate)
{
bool rtn=true;
if(strDate==string.Empty || strDate==null)
{
rtn=false;
}
else
{
try
{
System.DateTime dt=Convert.ToDateTime(strDate);
}
catch
{
rtn=false;
}
}
return rtn;
}
|