C#正则表达式编程(四)转致周公

正则表达式提供了功能强大、灵活而又高效的方法来处理文本。正则表达式的全面模式匹配表示法使您可以快速分析大量文本以找到特定的字符模式;提取、编辑、替换或删除文本子字符串;或将提取的字符串添加到集合以生成报告。对于处理字符串(例如 HTML 处理、日志文件分析和 HTTP 标头分析)的许多应用程序而言,正则表达式是不可缺少的工具。正则表达式是一个非常有用的技术,有人曾称之为能让程序员不至于丢掉饭碗的十大技术之一,可见它的重要性。

熟悉 DOS 或者命令行的朋友或许已经用过类似的功能,比如我们要查找 D 盘下所有的低于 Word2007 版本的 Word 文件(因为低于 Word2007 版本的 Word 文件的文件后缀是 .doc ,而 Word2007 版本的 Word 文件的文件后缀是 .docx ),我们可以在命令行下执行这个命名:

dir D:/*doc

当然如果想查找 D 盘下任意级子目录下的所有此类文件,就应该执行 dir /s D:/*doc 了。

注意正则表达式并不是在 C# 中独有的东东,实际上在其它语言中早就实现了,比如 Perl (可能很多人没有听说过这个编程语言,十年前大学期间我曾经学过一点皮毛),其它的编程语言 Java 、 PHP 及 JavaScript 等也支持正则表达式,正则表达式差不多像 SQL 语言一样成为标准了,同样和 SQL 类似,在不同的数据库厂商那里对SQL 标准支持的程度并不完全一样,正则表达式也是如此,大部分内的正则表达式可以跨语言使用,但是在各语言中也会有细微的区别,这一点是需要我们注意的。

正则表达式元字符

正则表达式语言由两种基本字符类型组成:原义(正常)文本字符和元字符。元字符使正则表达式具有处理能力。元字符既可以是放在 [] 中的任意单个字符(如 [a] 表示匹配单个小写字符 a ),也可以是字符序列(如 [a-d] 表示匹配 a 、 b 、 c 、 d 之间的任意一个字符,而 /w 表示任意英文字母和数字及下划线),下面是一些常见的元字符:

元字符

说明

.

匹配除 /n 以外的任何字符(注意元字符是小数点)。

[abcde]

匹配 abcde 之中的任意一个字符

[a-h]

匹配 a 到 h 之间的任意一个字符

[^fgh]

不与 fgh 之中的任意一个字符匹配

/w

匹配大小写英文字符及数字 0 到 9 之间的任意一个及下划线,相当于 [a-zA-Z0-9_]

/W

不匹配大小写英文字符及数字 0 到 9 之间的任意一个,相当于 [^a-zA-Z0-9_]

/s

匹配任何空白字符,相当于 [ /f/n/r/t/v]

/S

匹配任何非空白字符,相当于 [^/s]

/d

匹配任何 0 到 9 之间的单个数字,相当于 [0-9]

/D

不匹配任何 0 到 9 之间的单个数字,相当于 [^0-9]

[/u4e00-/u9fa5]

匹配任意单个汉字(这里用的是 Unicode 编码表示汉字的 )

正则表达式限定符

上面的元字符都是针对单个字符匹配的,要想同时匹配多个字符的话,还需要借助限定符。下面是一些常见的限定符 ( 下表中 n 和 m 都是表示整数,并且 0<n<m) :

限定浮

说明

*

匹配 0 到多个元字符,相当于 {0,}

?

匹配 0 到 1 个元字符,相当于 {0,1}

{n}

匹配 n 个元字符

{n,}

匹配至少 n 个元字符

{n,m}

匹配 n 到 m 个元字符

+

匹配至少 1 个元字符,相当于 {1,}

/b

匹配单词边界

^

字符串必须以指定的字符开始

$

字符串必须以指定的字符结束

说明:

( 1 )由于在正则表达式中“ / ”、“ ? ”、“ * ”、“ ^ ”、“ $ ”、“ + ”、“(”、“)”、“ | ”、“ { ”、“ [ ”等字符已经具有一定特殊意义,如果需要用它们的原始意义,则应该对它进行转义,例如希望在字符串中至少有一个“ / ”,那么正则表达式应该这么写: //+ 。

( 2 )可以将多个元字符或者原义文本字符用括号括起来形成一个分组,比如 ^(13)[4-9]/d{8}$ 表示任意以 13 开头的移动手机号码。

( 3 )另外对于中文字符的匹配是采用其对应的 Unicode 编码来匹配的,对于单个 Unicode 字符,如 /u4e00 表示汉字“一”, /u9fa5 表示汉字“龥”,在 Unicode编码中这分别是所能表示的汉字的第一个和最后一个的 Unicode 编码,在 Unicode 编码中能表示 20901 个汉字。

( 4 )关于 /b 的用法,它代表单词的开始或者结尾,以字符串“ 123a 345b 456 789d ”作为示例字符串,如果正则表达式是“ /b/d{3}/b ”,则仅能匹配 456 。

( 5 )可以使用“ | ”来表示或的关系,例如 [z|j|q] 表示匹配 z 、 j 、 q 之中的任意一个字母。

正则表达式分组

将正则表达式的一部分用 () 括起来就可以形成一个分组,也叫一个子匹配或者一个捕获组。例如对于“ 08:14:27 ”这样格式的时间,我们可以写如下的正则表达式:

((0[1-9])|(1[0-9])|(2[0-3])(:[0-5][1-9]){2}

如果以这个作为表达式,它将从下面的一段 IIS 访问日志中提取出访问时间(当然分析 IIS 日志最好的工具是 Log Parser 这个微软提供的工具):

00:41:23 GET /admin_save.asp 202.108.212.39 404 1468 176

01:04:36 GET /userbuding.asp 202.108.212.39 404 1468 176

10:00:59 GET /upfile_flash.asp 202.108.212.39 404 1468 178

12:59:00 GET /cp.php 202.108.212.39 404 1468 168

19:23:04 GET /sqldata.php 202.108.212.39 404 1468 173

23:00:00 GET /Evil-Skwiz.htm 202.108.212.39 404 1468 176

23:59:59 GET /bil.html 202.108.212.39 404 1468 170

如果我们想对上面的 IIS 日志进行分析,提取每条日志中的访问时间、访问页面、客户端 IP 及服务器端响应代码(对应 C# 中的 HttpStatusCode ),我们可以按照分组的方式来获取。

代码如下:

 

[c-sharp] view plaincopy
  1. private String text= @"00:41:23 GET /admin_save.asp 202.108.212.39 404 1468 176  
  2. 01:04:36 GET /userbuding.asp 202.108.212.39 404 1468 176  
  3. 10:00:59 GET /upfile_flash.asp 202.108.212.39 404 1468 178  
  4. 12:59:00 GET /cp.php 202.108.212.39 404 1468 168  
  5. 19:23:04 GET /sqldata.php 202.108.212.39 404 1468 173  
  6. 23:00:00 GET /Evil-Skwiz.htm 202.108.212.39 404 1468 176  
  7. 23:59:59 GET /bil.html 202.108.212.39 404 1468 170";  
  8. /// <summary>  
  9. /// 分析IIS日志,提取客户端访问的时间、URL、IP地址及服务器响应代码  
  10. /// </summary>  
  11. public void AnalyzeIISLog()  
  12. {  
  13.     //提取访问时间、URL、IP地址及服务器响应代码的正则表达式  
  14.     //大家可以看到关于提取时间部分的子表达式比较复杂,因为做了比较严格的时间匹配限制  
  15.     //注意为了简化起见,没有对客户端IP格式进行严格验证,因为IIS访问日志中也不会出现不符合要求的IP地址  
  16.     Regex regex = new Regex(@"((0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9]){2})/s(GET)/s([^/s]+)/s(/d{1,3}(/./d{1,3}){3})/s(/d{3})", RegexOptions.None);  
  17.     MatchCollection matchCollection = regex.Matches(text);  
  18.     for (int i = 0; i < matchCollection.Count; i++)  
  19.     {  
  20.         Match match = matchCollection[i];  
  21.         Console.WriteLine("Match[{0}]========================", i);  
  22.         for (int j = 0; j < match.Groups.Count; j++)  
  23.         {  
  24.             Console.WriteLine("Groups[{0}]={1}", j, match.Groups[j].Value);  
  25.         }  
  26.     }  
  27. }  

 

这段代码的输出结果如下:

Match[0]========================

Groups[0]=00:41:23 GET /admin_save.asp 202.108.212.39 404

Groups[1]=00:41:23

Groups[2]=00

Groups[3]=:23

Groups[4]=GET

Groups[5]=/admin_save.asp

Groups[6]=202.108.212.39

Groups[7]=.39

Groups[8]=404

Match[1]========================

Groups[0]=01:04:36 GET /userbuding.asp 202.108.212.39 404

Groups[1]=01:04:36

Groups[2]=01

Groups[3]=:36

Groups[4]=GET

Groups[5]=/userbuding.asp

Groups[6]=202.108.212.39

Groups[7]=.39

Groups[8]=404

Match[2]========================

Groups[0]=10:00:59 GET /upfile_flash.asp 202.108.212.39 404

Groups[1]=10:00:59

Groups[2]=10

Groups[3]=:59

Groups[4]=GET

Groups[5]=/upfile_flash.asp

Groups[6]=202.108.212.39

Groups[7]=.39

Groups[8]=404

Match[3]========================

Groups[0]=12:59:00 GET /cp.php 202.108.212.39 404

Groups[1]=12:59:00

Groups[2]=12

Groups[3]=:00

Groups[4]=GET

Groups[5]=/cp.php

Groups[6]=202.108.212.39

Groups[7]=.39

Groups[8]=404

Match[4]========================

Groups[0]=19:23:04 GET /sqldata.php 202.108.212.39 404

Groups[1]=19:23:04

Groups[2]=19

Groups[3]=:04

Groups[4]=GET

Groups[5]=/sqldata.php

Groups[6]=202.108.212.39

Groups[7]=.39

Groups[8]=404

Match[5]========================

Groups[0]=23:00:00 GET /Evil-Skwiz.htm 202.108.212.39 404

Groups[1]=23:00:00

Groups[2]=23

Groups[3]=:00

Groups[4]=GET

Groups[5]=/Evil-Skwiz.htm

Groups[6]=202.108.212.39

Groups[7]=.39

Groups[8]=404

Match[6]========================

Groups[0]=23:59:59 GET /bil.html 202.108.212.39 404

Groups[1]=23:59:59

Groups[2]=23

Groups[3]=:59

Groups[4]=GET

Groups[5]=/bil.html

Groups[6]=202.108.212.39

Groups[7]=.39

Groups[8]=404

从上面的输出结果中我们可以看出在每一个匹配结果中,第 2 个分组就是客户端访问时间(因为索引是从 0 开始的,所以索引顺序为 1 ,以下同理),第 6 个分组是访问的 URL (索引顺序为 6) ,第 7 个分组是客户端 IP (索引顺序为 6) ,第 9 个分组是服务器端响应代码(索引顺序为 9) 。如果我们要提取这些元素,可以直接按照索引来访问这些值就可以了,这样比我们不采用正则表达式要方便多了。

命名捕获组

上面的方法尽管方便,但也有一些不便之处:假如需要提取更多的信息,对捕获组进行了增减,就会导致捕获组索引对应的值发生变化,我们就需要重新修改代码,这也算是一种硬编码吧。有没有比较好的办法呢?答案是有的,那就是采用命名捕获组。

就像我们使用 DataReader 访问数据库或者访问 DataTable 中的数据一样,可以使用索引的方式(索引同样也是从 0 开始),不过如果变化了 select 语句中的字段数或者字段顺序,按照这种方式获取数据就需要重新变动,为了适应这种变化,同样也允许使用字段名作为索引来访问数据,只要数据源中存在这个字段而不管顺序如何都会取到正确的值。在正则表达式中命名捕获组也可以起到同样的作用。

普通捕获组表示方式: ( 正则表达式 ) ,如 (/d{8,11}) ;

命名捕获组表示方式: (?< 捕获组命名 > 正则表达式),如 (?<phone>/d{8,11})

对于普通捕获组只能采用索引的方式获取它对应的值,但对于命名捕获组,还可以采用按名称的方式访问,例如 (?<phone>/d{8,11}) ,在代码中就可以按照match.Groups["phone"] 的方式访问,这样代码更直观,编码也更灵活,针对刚才的对 IIS 日志的分析,我们采用命名捕获组的代码如下:

 

[c-sharp] view plaincopy
  1. private String text= @"00:41:23 GET /admin_save.asp 202.108.212.39 404 1468 176  
  2. 01:04:36 GET /userbuding.asp 202.108.212.39 404 1468 176  
  3. 10:00:59 GET /upfile_flash.asp 202.108.212.39 404 1468 178  
  4. 12:59:00 GET /cp.php 202.108.212.39 404 1468 168  
  5. 19:23:04 GET /sqldata.php 202.108.212.39 404 1468 173  
  6. 23:00:00 GET /Evil-Skwiz.htm 202.108.212.39 404 1468 176  
  7. 23:59:59 GET /bil.html 202.108.212.39 404 1468 170";  
  8. /// <summary>  
  9. /// 采用命名捕获组提取IIS日志里的相关信息  
  10. /// </summary>  
  11. public void AnalyzeIISLog2()  
  12. {  
  13.     Regex regex = new Regex(@"(?<time>(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9]){2})/s(GET)/s(?<url>[^/s]+)/s(?<ip>/d{1,3}(/./d{1,3}){3})/s(?<httpCode>/d{3})", RegexOptions.None);  
  14.     MatchCollection matchCollection = regex.Matches(text);  
  15.     for (int i = 0; i < matchCollection.Count; i++)  
  16.     {  
  17.         Match match = matchCollection[i];  
  18.         Console.WriteLine("Match[{0}]========================", i);  
  19.         Console.WriteLine("time:{0}", match.Groups["time"]);  
  20.         Console.WriteLine("url:{0}", match.Groups["url"]);  
  21.         Console.WriteLine("ip:{0}", match.Groups["ip"]);  
  22.         Console.WriteLine("httpCode:{0}", match.Groups["httpCode"]);  
  23.     }  
  24. }  

 

这段代码的执行效果如下:

Match[0]========================

time:00:41:23

url:/admin_save.asp

ip:202.108.212.39

httpCode:404

Match[1]========================

time:01:04:36

url:/userbuding.asp

ip:202.108.212.39

httpCode:404

Match[2]========================

time:10:00:59

url:/upfile_flash.asp

ip:202.108.212.39

httpCode:404

Match[3]========================

time:12:59:00

url:/cp.php

ip:202.108.212.39

httpCode:404

Match[4]========================

time:19:23:04

url:/sqldata.php

ip:202.108.212.39

httpCode:404

Match[5]========================

time:23:00:00

url:/Evil-Skwiz.htm

ip:202.108.212.39

httpCode:404

Match[6]========================

time:23:59:59

url:/bil.html

ip:202.108.212.39

httpCode:404

采用命名捕获组之后使访问捕获组的值更直观了,而且只要命名捕获组的值不发生变化,其它的变化都不影响原来的代码。

非捕获组

如果经常看别人有关正则表达式的源代码,可能会看到形如 (?: 子表达式 ) 这样的表达式,这就是非捕获组,对于捕获组我们可以理解,就是在后面的代码中可以通过索引或者名称(如果是命名捕获组)的方式来访问匹配的值,因为在匹配过程中会将对应的值保存到内存中,如果我们在后面不需要访问匹配的值那么就可以告诉程序不用在内存中保存匹配的值,以便提高效率减少内存消耗,这种情况下就可以使用非捕获组,例如在刚刚分析 IIS 日志的时候我们对客户端提交请求的方式并不在乎,在这里就可以使用非捕获组,如下:

 

[c-sharp] view plaincopy
  1. Regex regex = new Regex(@"(?<time>(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9]){2})/s(?:GET)/s(?<url>[^/s]+)/s(?<ip>/d{1,3}(/./d{1,3}){3})/s(?<httpCode>/d{3})";   

 

 

零宽度断言

关于零宽度断言有多种叫法,也有叫环视、也有叫预搜索的,我这里采用的是 MSDN 中的叫法,关于零宽度断言有以下几种:

(?= 子表达式 ): 零宽度正预测先行断言。仅当子表达式在此位置的右侧匹配时才继续匹配。例如, 19(?=99) 与跟在 99 前面的 19 实例匹配。

(?! 子表达式 ): 零宽度负预测先行断言。仅当子表达式不在此位置的右侧匹配时才继续匹配。例如, (?!99) 与不以 99 结尾的单词匹配,所以不与 1999 匹配。

(?<= 子表达式 ): 零宽度正回顾后发断言。仅当子表达式在此位置的左侧匹配时才继续匹配。例如, (?<=19)99 与跟在 19 后面的 99 的实例匹配。此构造不会回溯。

(?<! 子表达式 ): 零宽度负回顾后发断言。仅当子表达式不在此位置的左侧匹配时才继续匹配。例如 (?<=19) 与不以 19 开头的单词匹配,所以不与 1999 匹配。

正则表达式选项

在使用正则表达式时除了使用 RegexOptions 这个枚举给正则表达式赋予一些额外的选项之外,还可以在在表达式中使用这些选项,如:

 

[c-sharp] view plaincopy
  1. Regex regex = new Regex("(?i)def");  

 

 

它与下面一句是等效的:

 

[c-sharp] view plaincopy
  1. Regex regex = new Regex("def", RegexOptions.IgnoreCase);  

 

 

采用 (?i) 这种形式的称之为内联模式,顾名思义就是在正则表达式中已经体现了正则表达式选项,这些内联字符与 RegexOptions 的对应如下:

IgnoreCase :内联字符为 i ,指定不区分大小写的匹配。

Multiline :内联字符为 m ,指定多行模式。更改 ^ 和 $ 的含义,以使它们分别与任何行的开头和结尾匹配,而不只是与整个字符串的开头和结尾匹配。

ExplicitCapture :内联字符为 n ,指定唯一有效的捕获是显式命名或编号的 (?<name> … ) 形式的组。这允许圆括号充当非捕获组,从而避免了由 (?: … ) 导致的语法上的笨拙。

Singleline :内联字符为 s ,指定单行模式。更改句点字符 (.) 的含义,以使它与每个字符(而不是除 /n 之外的所有字符)匹配。

IgnorePatternWhitespace :内联字符为 x ,指定从模式中排除非转义空白并启用数字符号 (#) 后面的注释。(有关转义空白字符的列表,请参见字符转义。) 请注意,空白永远不会从字符类中消除。

举例说明:

 

[c-sharp] view plaincopy
  1. RegexOptions option=RegexOptions.IgnoreCase|RegexOptions.Singleline;  
  2. Regex regex = new Regex("def", option);  

 

用内联的形式表示为:

 

[c-sharp] view plaincopy
  1. Regex regex = new Regex("(?is)def");  

 

 

说明,其实关于正则表达式还有比较多的内容可以讲,比如反向引用、匹配顺序及几种匹配模式的区别和联系等,不过这些在日常开发中使用不是太多(如果做文本分析处理还是会用到的),所以暂时不会继续讲了。尽管本系列四篇文章篇幅都不是太长(本人不敢太熬夜了,因为每天 5 点多就要起床),不过通过这些基础的学习仍是可以掌握正则表达式的精华之处的,至于在开发中怎么样去用,就要靠我们自己灵活去结合实际情况用了。我个人经验是如果是用于验证是否满足要求,那么写正则表达式时写得严格一点,如果是从规范格式的文本中提取数据,则可以写得宽松一点,比如验证时间,则必须写成 (?<time>(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9]){2}) 这种形式,这样别人输入 26:99:99 就不能通过验证,但是如果是像从上面提到的 IIS 日志中提取时间,用 (?<time>/d{2}(:/d{2}){2}) 这种方式也是可以,当然如果写比较严格的验证比较麻烦时也可以写比较宽松的格式,然后借助其它手段来验证,在网上有一个验证日期的正则表达式,编写者充分考虑到各个月份天数的不同、甚至平年和闰年 2 月份天数的不同的情况写了一个相当复杂的正则表达式来验证,个人觉得可以结合将文本值转换成日期的方式来共同验证,这样更好理解和接受些。

到此,关于正则表达式的文章就暂时写到这里了,其它还有一些知识用得不是太多,以后有时间再总结了,接下来我可能要比较一下 ADO.NET 与 ORM 。

周公

2010-03-09

转载于:https://www.cnblogs.com/luodao1991/archive/2013/05/11/3073455.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/295517.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Quartz 的SB问题 GetNextValidTimeAfter 输出和输出 时区 不同步,好傻的方法?

测试代码如下DateTime kk new DateTime(2012, 6, 4, 15, 0, 0);Quartz.CronExpression cron new Quartz.CronExpression("0 14 15 ? * *");var dt cron.GetNextValidTimeAfter(kk);好傻好伤。dt的时候是 {2012/6/5 7:14:00} 跑出了一个7点来了。正确的期待值应该…

Android之switch控件的用法

在做一个蓝牙开关时候,用到了switch,记一下用法,其实跟Button是几乎一样的. 布局中: <Switch android:id="@+id/open" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textOff="蓝牙关闭中&q…

pythonresponse对象的属性_Scrapy中response属性以及内容提取

PythonPython开发Python语言Scrapy中response属性以及内容提取一.属性url &#xff1a;HTTP响应的url地址,str类型status&#xff1a;HTTP响应的状态码, int类型headers &#xff1a;HTTP响应的头部, 类字典类型, 可以调用get或者getlist方法对其进行访问body&#xff1a;HTTP响…

【转】学习apicloud和IOS之间的模块化使用

最近公司有使用APICloud发开的需求&#xff0c;需要我这边提供一些模块包得封装。因为没有也是刚接触APICloud&#xff0c;所以也就在看官方文档 。下面讲一讲我再使用过程中得一点点东西。 首先&#xff0c;下载官方SDK,下载最新版本的模块开发SDK&#xff0c;找到里面的Modul…

豪横!学术圈“造假之王”,200余篇论文有183篇论文被撤稿

全世界只有3.14 % 的人关注了爆炸吧知识导读&#xff1a;学术造假已经不再是什么新鲜话题&#xff0c;历史上的学术骗子也是数不胜数。其中骗子之王更是达到前无古人的地步&#xff0c;发表论文数212篇&#xff0c;因涉嫌造假而遭到撤稿的就达到了183篇之多。然而打假的过程并不…

在CISCO ASA 防火墙上配置Web ×××

目前市场上产品很多&#xff0c;而且技术各异&#xff0c;就比如传统的 IPSec 来讲&#xff0c; SSL 能让公司实现更多远程用户在不同地点接入&#xff0c;实现更多网络资源访问&#xff0c;且对客户端设备要求低&#xff0c;因而降低了配置和运行支撑成本。很多企业用户采纳 …

学Dapr Actors 看这篇就够了

介绍Actor模式将Actor描述为最低级别的“计算单元”。换句话说&#xff0c;您在一个独立的单元&#xff08;称为actor&#xff09;中编写代码&#xff0c;该单元接收消息并一次处理一个消息&#xff0c;没有任何并发或线程。再换句话说&#xff0c;根据ActorId划分独立计算单元…

博客园2013年5月份第1周源码发布详情

媒体互动学习社区(课程设计)源码 2013-5-10 [VS2010]源码描述&#xff1a;该源码使用VS210SQL08开发&#xff0c;主要分为前台和后台&#xff0c;所有提交使用JQFORM提交&#xff0c;实现无刷新提高用户的体验&#xff0c;前台功能有学科的介绍&#xff0c;课件跟视频下载&…

git之Pushing to the remote branch is not fast-forward错误解决

今天推送代码的时候报错了这个Pushing to the remote branch is not fast-forward,so the push has to be forced.The commits in the remote branch will be lost 错误&#xff0c;然后就出现这个效果&#xff0c;下面是图片。 问题&#xff08;Non-fast-forward&#xff09;的…

tp mysql索引_mysql索引

1 查看表中已存在哪些索引&#xff1a;show index from 表名&#xff1b;在添加索引之前最好先查看一下该表中已存在哪些索引&#xff1a;show index from 表名&#xff1b;1、主键索引注意&#xff1a; 主键索引一张表中只能有一个&#xff0c;但是可以添加多个索引 比如&…

CSS Id 和 Class

2019独角兽企业重金招聘Python工程师标准>>> id 和 class 选择器 如果你要在HTML元素中设置CSS样式&#xff0c;你需要在元素中设置"id" 和 "class"选择器。 id 选择器 id 选择器可以为标有特定 id 的 HTML 元素指定特定的样式。 HTML元素以id属…

这4部有生之年必看的“教材级”纪录片,免费领取!

全世界只有3.14 % 的人关注了爆炸吧知识纪录片是以真实生活为创作素材&#xff0c;以真人真事为表现对象&#xff0c;并对其进行艺术的加工与展现的&#xff0c;以展现真实为本质&#xff0c;并用真实引发人们思考的电影或电视艺术形式。好的纪录片就像打开了一扇新世界的大门&…

Dapr 集成 APISIX 做API网关

在这篇文章中&#xff0c;我将展示如何创建一个 APISIX控制器&#xff0c;该控制器在 Kubernetes 集群中公开启用 Dapr 的应用程序。本质上&#xff0c;APISIX控制器将配置相同的标准 Dapr annotations以注入daprd sidecar。通过公开这个 sidecar&#xff0c;它将允许外部应用程…

判断一个字符串是否包含另一个字符串(用java但是不能用index()这个函数)

目录: 一.方法介绍 二.图示意 三.源代码 一.方法介绍 判断一个字符串str1是否包含另一个字符串str2: 1.取str2的第一个字符一次和str1的字符依次比较,知道找到相等的字符为止或者找完整个str1的length. 2.当找到相等的字符后,在str2长度内str2与str1依次进行比较 二…

mysql添加字段时定义候选键_MySQL 表约束

约束概述对数据表中数据的限制条件叫表的约束&#xff0c;目的是为了保证表中记录的完整和有效。例如非空、唯一等。查看约束1 通过查看建表语句 查看表中的约束show create table tb_name;2 通过检查约束表 查看约束select * from information_schema.table_constraints where…

跳槽9招让你“空降”任何企业都能成功

2019独角兽企业重金招聘Python工程师标准>>> 作为一名职业经理人&#xff0c;没有谁没跳过槽&#xff0c;撇开在跳槽时对所“空降”的企业所需要的行业知识知根知底而“得心应手”&#xff0c;从而“稳定”外&#xff0c;其他人可能或多或少都有过因“不适应”新单位…

这个年纪,喜欢你的肉体还会送你包的,原来是......

1 iPhone 12一出王守义成最大赢家&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼2 想搭免费车的喵&#xff08;dy&#xff1a;大兔几&#xff09;▼3 拼纹身的有吗&#xff1f;纹在我身&#xff0c;刀在你身▼4 那你泡啥&#xff1f;▼5 快把知识君p上去&#xff…

Response. AppendHeader使用大全及文件下载.net函数使用注意点(转载)

Response. AppendHeader使用大全文件下载&#xff0c;指定默认名 Response.AddHeader(”content-type”,”application/x-msdownload”); Response.AddHeader(”Content-Disposition”,”attachment;filename要下载的文件名.rar”); 刷新页面 Response.AddHeader “REFRESH”, …

C# WPF MVVM模式Caliburn.Micro框架下事件发布与订阅

01—前言处理同模块不同窗体之间的通信和不同模块之间不同窗体的通信&#xff0c;Caliburn提供了一种事件机制&#xff0c;可以在应用程序中低耦合的模块之间进行通信&#xff0c;该机制基于事件聚合器服务&#xff0c;允许发布者和订阅者之间通过事件进行通讯&#xff0c;且彼…

mysql触发器 node_node.js中事件触发器events的使用

node.js是基于事件驱动的&#xff0c;通过events&#xff0c;我们可以方便的创建事件&#xff0c;并通过触发事件来调用我们自定义的监听函数。所有能触发事件的对象都应该是 EventEmitter 类的实例&#xff0c;一般我们自定义一个类继承于 EventEmitter 类。通过on()方法我们可…