正则表达式_字符匹配/可选字符集

news2024/12/24 20:34:28

正则表达式(Regular Expression)也叫匹配模式(Pattern),用来检验字符串是否满足特 定规则,或从字符串中捕获满足特定规则的子串。

字符匹配

最简单的正则表达式由“普通字符”和“通配符”组成。比如“Room\d\d\d”就这样 的正则表达式。 这些位置是普通字符 R o o m \d \d \d 20 这 3 个位置各匹配一个数字 其中“Room”是普通字符,而“\d”是通配符,表示该位置上有一个数字。该表达式 共占用了 7 个位置,第一个位置上是字母“R”,第二个位置和第三个位置上都是字母“o”, 第四个位置上是字母“m”,而第五到第七个位置上是三个数字。所以正则表达式 “Room\d\d\d”代表着“以Room开头,以三个数字结尾”的那一类字符串。比如字符串 “Room101”、“Room415”、“Room888”等都与“Room\d\d\d”匹配① 。

用于正则表达式的通配符如下 所示,每个通配符都代表一类字符

 

.NET 提供了一批与正则表达式相关的类,它们都位于 System.Text.RegularExpressions 命名空间,现在我们来学习最主要的 Regex 类,并用它来匹配正则表达式。 Regex 类的部分方法如表 20-2 所示 

现在假设某份文件里包含着 Kitty 的房间号码(格式为 RoomXXX),档案很长,人 工查阅很耗时间,那么如何通过计算机帮我们找到房间号码呢? 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
//注意在文件头引用命名空间 System.Text.RegularExpressions。

namespace Pattern202405
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string text = "The Colony is a beautiful town...Kitty lives in Room415...";
            //正则表达式
            Regex expression = new Regex(@"Room\d\d\d");
            //找出所有匹配的字符串,放入集合中
            MatchCollection matches = expression.Matches(text);
            //输出匹配的字符串
            foreach (Match match in matches)
            {
                Console.WriteLine("She lives in {0}", match);
                Console.ReadKey();
            }

        }
    }
}

--------------------------------------- 

可选字符集

除了通配符外,我们还可以把某个位置上允许出现的字符写在方括号[]内,组成可选字符集,比如 

[abc]表示该位置可以出现字母 a、b、c 
[A-D]表示该位置可以出现字母 A、B、C、D 
[A-DM-P]表示该位置可以出现字母 A 到 D 或 M 到 P 
[A-Da-d]表示该位置可以出现字母 A 到 D 或 a 到 d 
[12] 表示该位置可以出现数字 1 或数字 2 
[1-5]表示该位置可以出现数字 1 到 5 
[0-57-9]表示该位置可以出现除 6 外的所有数字
[\s\S]表示该位置可以出现任何字符,包括任何可见字符和不可见字符(如空格、制表符、换行等)

如果想从字符串中找出名字以 V 或 R 开头,出生于 80~90 年代的男孩,可以用下面
的正则表达式:
[VR] [a-z] [a-z] [a-z] [a-z] - 1 9 [89] [0-9] 

它匹配的字符串包含 10 个字符,第 1 个字符为“V 或 R”,第 2~5 个字符为“a 到 z 的某个小写字母”,第 6~8 个字符为“-19”,第 9 个字符为“数字 8 或 9”,第 10 个字 符为“0 到 9 之间的某个数字”。 注意,不管中括号看起来有多长,它都只代表一个字符。表达式中的[VR]、[a-z]、[89]、 [0-9]都是一个字符,不能看作多个字符。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Pattern202405_2
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string boys = "Vitor-1979 Verne-1982 Regan-1998 Robin-2008";
            //string text = "Vitor-1970 Verne-1982 Regan-1998 Robin2008";
            //正则表达式
            Regex expression = new Regex(@"[VR][a-z][a-z][a-z][a-z]-19[89][0-9]");
            //获取并输出匹配的字符串
            foreach (Match match in expression.Matches(boys))
            {
                Console.WriteLine(match);
               
            }
            Console.ReadKey();
        }
    }
}

 启动程序:

 反向字符集

 在中括号表达式中用符号“^”表示“非”。比如

[^x] 匹配除 x 以外的所有字符
[^abc] 匹配除 a、b、c 以外的所有字符
[^0-9] 匹配除 0 到 9 以外的所有字符
[^#] 匹配除#以外的所有字符
[^\n] 匹配除换行符\n 以外的所有字符

string sentence = "bog dog fog hog log"; 
//正则表达式
Regex expression = new Regex(@"[^bd]og"); 
//输出匹配的字符串
foreach (Match match in expression.Matches(sentence )) 

 Console.WriteLine(match); 
}

正则表达式“[^bd]og”匹配的字符串包含三个字符,第一个字符 是除 b 和 d 以外的字符,后两个字符为 og 

或匹配

在正则表达式中用符号“|”表示“或”。比如
"x|y" 匹配 "x"或"y" 
"good|ok" 匹配 "good"或"ok" 
"(tr|b)ee" 匹配 "tree"或"bee" 
"th(i|a)nk" 匹配 "think"或"thank" 
"Book One|Two" 匹配 "Book One"或"Two" 
"Book (One|Two)" 匹配 "Book One"或"Book Two" 

数量限定符

假设我们要从一串人名中找出以 V 开头的人名,因为人名的长度不是固定的,所以用 一一对应的方法就无法实现,这时需要使用数量限定符

数量限定符“*”将前面的字符重复 0 次或多次。

string words = "lg log loog looog loooog looooog"; 
//正则表达式
Regex expression = new Regex("lo*g"); 
//获取并输出匹配的字符串
foreach (Match match in expression.Matches(words)) 

 Console.WriteLine(match); 

正则表达式“lo*g”表示字符串的第一个字符为 l,最后一个字符为 g,中间有零个或
多个字母 o。运行结果如图 所示

数量限定符“+”将前面的字符重复 1 次或多次 
//正则表达式 Regex expression = new Regex("lo+g"); 

数量限定符“?”将前面的字符重复 0 次或 1 次。 
//正则表达式 Regex expression = new Regex("lo?g");

数量限定符{n,}表示把它前面的字符至少重复 n 遍
//正则表达式 Regex expression = new Regex("lo{3}g");
正则表达式“lo{3}g”表示字符串的第一个字符为 l,最 后一个字符为 g,中间有 3 个字母 o。

数量限定符{n,m}把前面的字符重复 n 至 m 遍
//正则表达式 Regex expression = new Regex("lo{2,4}g");
正则表达式“lo{2,4}g”表示字符串的第一个字符为 l,最后一个字符为 g,中间有 2 到 4 个字母 o。

正则表达式“l(eo)+g”表示字符串的第一个字符为 l,最后一个字符为 g,中间有一个 或多个 eo。

 最奇妙的是这些数量限定符还可以与通配符组合。比如通配符“\w”匹配任意单词字 符,限定符“*”表示把前面的字符重复 0 次或多次,所以正则表达式“\w*”匹配由任意 单词字符组成的任意长度的字符串。

string girls = @"Van is 16; Vicky is 18; Vivien is 19; Vinvcent is 22"; 
 Regex expression = new Regex(@"V\w* is \d\d"); 
 foreach (Match match in expression.Matches(girls)) 
 { 
 Console.WriteLine(match); 
 } 

贪婪和懒惰 的限定符

“贪婪的”(Greedy),它们会匹配尽可能多的文本。如果在限定符后 加上?号,它就会变成“懒惰的”(Lazy),会匹配尽可能少的文本。

限定符“<.*>”和“<.*?>”都表示以“<”开头,以“>”结尾,中间是若干个字符的字符串,

贪婪限定符尽量找到一个最长(保留中间可能的匹配)的结果,而懒惰限定符尽量找最短的结 果(忽略中间可能的匹配)。 在匹配以特定字符为首尾的字符串时,懒惰的限定符往往能轻松的达到目的。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace 贪婪和懒惰
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string words = "ab<H1>Hello World</H1>c";
            //贪婪的限定符
            Regex expression1 = new Regex("<.*>");
            MatchCollection matchs1 = expression1.Matches(words);
            Console.WriteLine("There is {0} match with greedy quantifier:", matchs1.Count);
            foreach (Match match in matchs1)
            {
                Console.WriteLine(match);
            }
            //懒惰的限定符
            Regex expression2 = new Regex("<.*?>");
            MatchCollection matchs2 = expression2.Matches(words);
            Console.WriteLine("There are {0} matchs with lazy quantifier:", matchs2.Count);
            foreach (Match match in matchs2)
            {
                Console.WriteLine(match);
            }
            Console.ReadKey();
        }
    }
}

 

 懒惰限定符,有两个匹配模式值得注意。一个是“{n}?”,它实际上与“{n}”是 等价的,因为不管是贪婪还是懒惰,都已经限定死了,只能重复 n 次。

另一个匹配模式是“??”,我们知道“?”表示把前面的字符重复 0 到 1 次,而“??”又是什么意思呢?

string sentence = "Where bee is, there is honey."; 
 //用?限定
 Regex expression1 = new Regex("be?"); 
 foreach (Match match in expression1.Matches(sentence)) 
 { 
 Console.WriteLine("be? = {0}", match); 
 } 
 //用??限定
 Regex expression2 = new Regex("be??"); 
 foreach (Match match in expression2.Matches(sentence)) 
 { 
 Console.WriteLine("be?? = {0}", match); 
 } 

运行结果如图
 

在正则表达式“be?”中,“?”并不是把整个单词 be 重复 0 到 1 次,而 是把“?”前面字母“e”重复 0 到 1 次。因为“be?”是贪婪的,能重复 1 次就不重复 0 次,所以结果中 e 出现了 1 次;

 而“be??”是懒惰的,重复次数要尽量少,所 以它选择把 e 重复 0 次

所有限定符都可以和“?”组合 

 

定位符 

通过定位符可以在指定位置寻找匹配的子串。 若正则表达式中使用了定位符“^”,则在整个字符串的头部寻找匹配的子串

string words = "year1998 year2008 year2018"; 
//正则表达式
Regex expression = new Regex(@"^year\d\d\d\d"); 
//获取并输出匹配的字符串
foreach (Match match in expression.Matches(words)) 

 Console.WriteLine(match); 
}

“^”匹配字符串的开头位置,所以“^year\d\d\d\d”表示要从字符串的开头位置开始寻 找。运行结果如图


若正则表达式中使用了定位符“$”,则在整个字符串的尾部寻找匹配的子串
//正则表达式 Regex expression = new Regex(@"year\d\d\d\d$");
“$”匹配字符串的结尾位置,所以“year\d\d\d\d$”表示匹配的子串紧邻字符串的结尾 位置。运行结果如图 所示

 

若正则表达式中使用了定位符“\b”,则在字符串中每个“单词”的边界①寻找匹配 的子串。 

 string words = "formfordfork"; 
 Console.Write("None anchors:"); 
 Regex expression = new Regex(@"for\w"); 
 foreach (Match match in expression.Matches(words)) 
 { 
 Console.Write(match + "\t"); 
 } 
Console.Write("\nAnchor start:"); 
 expression = new Regex(@"\bfor\w"); 
 foreach (Match match in expression.Matches(words)) 
 { 
 Console.Write(match + "\t"); 
 } 
 Console.Write("\n Anchor end:"); 
 expression = new Regex(@"for\w\b"); 
 foreach (Match match in expression.Matches(words)) 
 { 
 Console.Write(match + "\t"); 
 } 

“\b”匹配单词的边界位置。运行结果如图  所示。由结果可以看出,当没有定位 符时,匹配单词中所有符合要求的子串;当定位符\b 在前面时,在单词的头部寻找匹配的子串当定位符\b 在后面时,在单词的结尾寻找匹配的子串 

 

常用正则表达式“\b\w+\b”找出一句话里的所有单词。 

用于正则表达式的定位符如表

 符号“^”和“$”在正则表达式中也有特殊用处,所以当要 匹配它们本身时也需使用它们的转义字符“\^”和“\$”。

 分组和后向引用

如果没有括号,正则表达式“tr|bee”匹配“tr”或“bee”,加了括号后,“(tr|b)ee”匹 配“tree”或“bee”,这种带括号的形式称为括号表达式。

括号表达式并不简单的起着确 定范围的作用,它同时会创建子表达式,每个子表达式形成一个分组,并把捕获到的与子 表达式匹配的子串保存在分组中,以供将来使用

举一个例子,电子邮件地址通常由用户名、二级域名、一级域名三部分构成。比 如 waterwood @163.com,其中 waterwood 为用户名,163 为二级域名,com 为一级域名。 我们可以通过下面的正则表达式匹配这类电子邮件地址:        "(\w+)@(\w+)\.(\w+)"

这里有三个括号,形成三个子表达式,就会出现三个分组。默认情况下,每个分组会 自动拥有一个组号,规则是:从左向右,按分组左括号的出现顺序进行编号,第一个分组 的组号为 1,第二个为 2,以此类推。在正则表达式里引用分组的语法为“\number”,比如 “\1”代表与分组 1 匹配的子串,“\2”代表与分组 2 匹配的字串,等等

如果出现嵌套的分组,它们的编号也按左括号的出现顺序排列。

 

存储起来的分组有什么作用呢?下面我们通过一个例子来说明。很多句子里会有 重复的单词,下面我们就通过正则表达式找出这些重复的单词

string text = "you are very very good"; 
 foreach (Match match in Regex.Matches(text, @"\b(\w+)\b \1\b")) 
 { 
 Console.WriteLine(match); 

运行结果如图  所示

我们前面已经知道“\b(\w+)\b”匹配一个单词,因为这里面有一个括号,所以会捕获 一个以 1 为组号的分组,后面的“\1”就代表这个分组,表示这个位置上出现和分组 1 一 样的内容。所以两者连起来就表示两个重复的单词。这种在后面的表达式中引用前面的分组的方式就叫做后向引用

除了匹配重复的单词,后向引用还有一个较为常见的应用,那就是匹配有效的 HTML 标签。我们知道,HTML 标签大多是成对出现的 

string words = "<h0>not valid</h1> <h2>valid</h2> <h3>not valid</h4>"; 
 foreach (Match match in Regex.Matches(words, @"<(.*?)>.*?</\1>")) 
 { 
 Console.WriteLine(match); 
 } 

运行结果如图

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

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

相关文章

1.pytorch加载收数据(B站小土堆)

数据的加载主要有两个函数&#xff1a; 1.dataset整体收集数据&#xff1a;提供一种方法去获取数据及其label&#xff0c;告诉我们一共有多少数据&#xff08;就是自开始把要的数据和标签都收进来&#xff09; 2.dataloader&#xff0c;后面传入模型时候&#xff0c;每次录入数…

C++类定义时成员变量初始化

在C11中允许在类定义时对成员变量初始化。 class A { public:A() { }void show(){cout << "m_a " << m_a << endl;cout << "m_b " << m_b << endl;} private:int m_a 10;//类定义时初始化int m_b; //没有初始化…

2024阿里云ctf-web-chain17学习

agent jdk17依赖有h2思路清晰打jdbc attack <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/com.aliba…

踏春正当时!VELO Prevail Ride带你探索多元骑行潮流体验~

嘿&#xff0c;朋友&#xff01;踏春正当时嘞&#xff01;在这个追求个性化与多元化的新时代&#xff0c;骑行爱好者们也开始寻找能适应各种骑行场景的理想坐垫。从悠闲自在的日常通勤&#xff0c;到热血沸腾的公路竞速&#xff0c;再到勇攀高峰的山地探险&#xff0c;维乐VELO…

更深层次理解传输层两协议【UDP | TCP】【UDP 缓冲区 | TCP 8种策略 | 三次握手四次挥手】

博客主页&#xff1a;花果山~程序猿-CSDN博客 文章分栏&#xff1a;Linux_花果山~程序猿的博客-CSDN博客 关注我一起学习&#xff0c;一起进步&#xff0c;一起探索编程的无限可能吧&#xff01;让我们一起努力&#xff0c;一起成长&#xff01; 目录 再谈端口号 端口号的返回…

C语言-整体内容简单的认识

目录 一、数据类型的介绍二、数据的变量和常量三、变量的作用域和生命周期四、字符串五、转义字符六、操作符六、常见的关键字6.1 关键字static 七、内存分配八、结构体九、指针 一、数据类型的介绍 sizeof是一个操作符&#xff0c;是计算机类型/变量所占内存空间的大小   sc…

AEC Capital Limited:开启可持续金融新纪元

在当今社会&#xff0c;环保和可持续发展已成为全球关注的焦点。在这个背景下&#xff0c;AEC Capital Limited作为香港的一家金融服务公司&#xff0c;以其专业、高端的服务和创新的理念&#xff0c;成为可持续金融领域的引领者。我们致力于将环境保护与金融服务相结合&#x…

设计模式之拦截过滤器模式

想象一下&#xff0c;在你的Java应用里&#xff0c;每个请求就像一场冒险旅程&#xff0c;途中需要经过层层安检和特殊处理。这时候&#xff0c;拦截过滤器模式就化身为你最可靠的特工团队&#xff0c;悄无声息地为每一个请求保驾护航&#xff0c;确保它们安全、高效地到达目的…

触动精灵纯本地离线文字识别插件

目的 触动精灵是一款可以模拟鼠标和键盘操作的自动化工具。它可以帮助用户自动完成一些重复的、繁琐的任务&#xff0c;节省大量人工操作的时间。但触动精灵的图色功能比较单一&#xff0c;无法识别屏幕上的图像&#xff0c;根据图像的变化自动执行相应的操作。本篇文章主要讲解…

C语言二分查找的区间问题

概念 什么是二分查找呢&#xff1f; 二分查找&#xff1a;在有序数组中查找某一特定元素的搜索算法。 二分查找又称折半查找&#xff0c;通过将数组折半&#xff0c;用中间值和查找值作比较&#xff0c;多次使用&#xff0c;直到找到要查找的值。 注意:二分查找的前提是&#…

内核workqueue框架

workqueue驱动的底半部实现方式之一就是工作队列&#xff0c;作为内核的标准模块&#xff0c;它的使用接口也非常简单&#xff0c;schedule_work或者指定派生到哪个cpu的schedule_work_on。 还有部分场景会使用自定义的workqueue&#xff0c;这种情况会直接调用queue_work和qu…

JavaScript的操作符运算符

前言&#xff1a; JavaScript的运算符与C/C一致 算数运算符&#xff1a; 算数运算符说明加-减*乘%除/取余 递增递减运算符&#xff1a; 运算符说明递增1-- 递减1 补充&#xff1a; 令a1&#xff0c;b1 运算a b ab12ab22ab--10a--b00 比较(关系)运算符&#xff1a; 运算…

服务器端集群优化-集群还是主从

7、服务器端集群优化-集群还是主从 集群虽然具备高可用特性&#xff0c;能实现自动故障恢复&#xff0c;但是如果使用不当&#xff0c;也会存在一些问题&#xff1a; 集群完整性问题集群带宽问题数据倾斜问题客户端性能问题命令的集群兼容性问题lua和事务问题 问题1、在Redi…

[Spring Cloud] (6)gateway整体加解密

文章目录 简述整体效果后端增加配置nacos增加配置GlobalConfig 添加请求整体解密拦截器DecryptionFilter添加响应整体解密拦截器EncryptionFilter 前端请求拦截器添加整体加密逻辑请求头中添加sessionId 响应拦截器添加整体解密逻辑 简述 本文网关gateway&#xff0c;微服务&a…

VsCode插件 -- Power Mode

一、安装插件 1. 首先在扩展市场里搜索 Power Mode 插件&#xff0c;如下图 二、配置插件 设置 点击小齿轮 打上勾 就可以了 第二种设置方法 1. 安装完成之后&#xff0c;使用快捷键 Ctrl Shift P 打开命令面板&#xff0c;在命令行中输入 settings.json &#xff0c; 选择首…

扩展学习|结合故事的力量和数字的力量:混合方法研究和混合研究综述

文献来源&#xff1a;Pluye, Pierre, and Quan Nha Hong. "Combining the power of stories and the power of numbers: mixed methods research and mixed studies reviews." Annual review of public health 35 (2014): 29-45. 文献获取&#xff1a;链接&#xff1…

【机器视觉】yolo-world-opencvsharp-.net4.8 C# 窗体应用程序

这段代码是基于 OpenCvSharp, OpenVinoSharp 和 .NET Framework 4.8 的 Windows Forms 应用程序。其主要目的是加载和编译机器学习模型&#xff0c;对输入数据进行推理&#xff0c;并显示结果。 下面是该程序的主要功能和方法的详细总结&#xff1a; 初始化 OpenVINO 运行时核心…

【微服务】配置管理

Nacos配置管理 配置管理配置共享配置热更新 配置管理 将微服务集群中常用&#xff0c;经常变化的配置都写到一个独立的配置文件微服务中进行统一管理 配置共享 在Nacos的界面当中进行配置管理&#xff0c;在配置列表中添加配置 比如各个服务中的jdbc的连接配置&#xff1a; …

【AI工具声音克隆】——OpenVoice一键部署modelScope一键使用

一、声音/音色克隆简介 声音或音色克隆的原理实现步骤主要基于深度学习技术&#xff0c;特别是语音合成和生成模型。以下是声音/音色克隆的大致实现步骤&#xff1a; 数据收集&#xff1a; 收集语音数据&#xff0c;作为模型的训练样本。数据应尽可能多样化&#xff0c;包括不…

基于stm32的USB虚拟U盘+FATFS+W25Q64

基于stm32的USB虚拟U盘FATFSW25Q64 本文目标&#xff1a;基于stm32的USB虚拟U盘FATFSW25Q64 按照本文的描述&#xff0c;简单跑通USB的MSC类来进行简单交互。 先决条件&#xff1a;拥有C语言基础&#xff0c;装有编译和集成的开发环境&#xff0c;比如&#xff1a;Keil uVis…