FileStream类、StreamReader类、StreamWrite类、StringBuilder类、字符串常用方法、正则表达式、断言、匹配日期(年月日)

112 阅读3分钟

一、大文件读取方式

1.FileStream文件流(操作字节可以读取各种文件信息)

(1)FileStream文件流和File的区别

File在读取文件的时候是一次性读取所有的文件信息,而FileStream是以文件流的形式一点点去读取文件的信息

(2)使用FileStream读取文件

image.png 注意点:Open不存在文件不会创建,会直接报错,而OpenOrCreate如果没有这个文件,就会创建一个文件;fs.Read(bytes)里面读取完返回的是实际上读取到的字节数

(3)使用FileStream写入文件信息

image.png 注意点:如果每次读取都要关闭文件流和释放资源,代码会很重复,这时候我们可以使用using,将读取或写入的代码进行包裹,这样我们可以不用关闭和释放资源

2.StreamReader和StreamWrite读写文本文件(读取字符信息)

1.StreamReader

image.png

2.StreamWriter

image.png 小练习:写一个程序逐行输入字符串,将每一行的内容写入到同个目录下的1.txt文件并换行,最后遇到q字符结束写入

image.png

二、字符串类String

1.关于字符串的几个方法

image.png

image.png

2.使用StringBuilder创建字符串

1.为什么要使用StringBuilder

如果我们频繁去删除和添加字符串中的内容,使用string生成的字符串我们知道每次更改会重新指向堆中新的数据,这样会重复删除新建数据非常耗性能,如果使用StringBuilder不会频繁申请内存空间,可以自动向后扩展

2.StringBuilder创建字符串的方式

image.png

三、正则表达式

1.正则表达式有什么用

image.png

2.正则表达式是什么

正则表达式其实就是由普通字符以及特殊字符(元字符)组成的文字模式,该模式描述在查找文字主体时待匹配的一个或多个字符串。

3.各种元字符

(1)字符类

[ char_group]:匹配字符组中的任意一个字符

[^char_group]:匹配除字符组之外的任意一个字符

[first-last]:匹配从first到last的字符范围中的任意一个字符,字符范围包括first和last。

.一个点:通配符,匹配除\n之外的任意一个字符

\w:匹配任意一个单词(word)字符,单词字符通常是指A-Z、a-z和0-9

\W:匹配任意一个非单词字符,是指除A-Z、a-z和0-9之外的字符

\s:匹配任意一个空白字符

\S:匹配任意一个非空白字符

\d:匹配任意一个数字字符

\D:匹配任意一个非数字字符
复制代码

(2)定位类

^:默认情况下,匹配字符串的开始位置;在多行模式下,匹配每行的开始位置;

$:默认情况下,匹配字符串的结束位置,或 字符串结尾的\n之前的位置;在多行模式下,匹配每行结束之前的位置,或者每行结尾的\n之前的位置。

\A:匹配字符串的开始位置;

\Z:匹配字符串的结束位置,或 字符串结尾的\n之前的位置;

\z:匹配字符串的结束位置;

\G:匹配上一个匹配结束的位置;

\b:匹配一个单词的开始或结束的位置;

\B:匹配一个单词的中间位置;
复制代码

(3)量词、贪婪和懒惰

*:规定前面字符出现0次或多次

+:出现1次或多次

?:出现0次或1次

{n}:出现n次

{n,}:出现至少n次

{n,m}:出现n到m次

x|y x或者y中的一个字符
复制代码

3.Regex.Replace()方法替换匹配出来的字符串

image.png

4.Regex.IsMatch(字符串,正则表达式)判断字符串是否符合正则表达式

image.png

5.匹配是否是正确的邮箱

邮箱的格式是qq号(5~12位数字)+@qq.com

6.匹配是否是正确的手机号

            string phone = @"^1[0-9]{10}";
            string str2 = "18379689417";
            Console.WriteLine(Regex.IsMatch(str2, phone));

image.png

7.Regex.Match(s,pattern)匹配第一个满足的字符串

image.png

8.Regex.Matches(s,pattern)匹配所有满足的字符串并返回出来

image.png

9.常见的几个正则表达式

image.png

10.正则表达式中的断言

(1)为什么需要断言

我们前面使用^和$来匹配子串在字符串中出现的位置,如果字符串的位置不是在最后或者最前面而是在某个字符之前,这个时候我们还想匹配出指定位置的字符串,就得使用断言。

(2)四种断言

正则名称含义示例
(?<=Y)肯定逆序断言左边是Y(?<=\d)th 左边是数字的 th,可以匹配上 9th
(?<!Y)否定逆序断言左边不是Y(?<!\d)th 左边不是数字的 th,可以匹配上 health
(?=Y)肯定顺序断言右边是Ysix(?=\d) 右边是数字的 six,可以匹配上 six6
(?!Y)否定顺序断言右边不是Ysix(?!\d) 右边不是数字的 six,可以匹配上 sixgod

(3)(?<=Y)和(?<!Y)

表示匹配出的子串左边必须是符合某种类型的字符串,<=表示左边是Y类型的,<!表示左边是非Y类型,比如匹配123abcd234fd中abcd后面的234,那么我们可以使用(?<=d)\d+表示满足数字的左边是字符d的子串,这样我们匹配出的就是234

image.png

image.png

(4)(?=Y)和(?!Y)

表示匹配出的子串右边必须是符合某种类型的字符串,=表示右边是Y类型,!表示右边是非Y类型,比如匹配123abcd234fd中所有在123和234中间的字符那么我们就可以使用(?<=y)和(?=y)一起来判断

image.png

11.提取正则表达式中某个满足条件的字符串Match.Groups

(1)根据编号拿到匹配的嵌入子串

image.png

(2)根据占位符匹配到括号中的子串

image.png

             //之前我们判断某个子串在我们字符串中的位置
            /*string pattern = @"$/d+";*/
            //string str = "abc123dfdf123c789"; //就想把数字匹配出来,并且数字必须在c字符后面
            //使用断言,作用:就是帮我们定位,找到满足的子串,定位位置左边和右边
            //1.左边的断言:(?<=条件):字符串必须满足左边是某个条件的正则 (?<!条件)
            //string pattern = @"(?<=c)\d+"; //括号中无参与匹配,只会帮我们定位
            /*string pattern = @"(?<!c)\d+"; //括号中无参与匹配,只会帮我们定位,!不匹配c后面是数字的子串
            MatchCollection mc = Regex.Matches(str, pattern);
            foreach(Match m in mc)
            {
                Console.WriteLine(m);*/

            //2.右边断言 (?=条件) (?!条件) 帮我们定位子串必须满足右边是某个正则条件的字符串
            /*string str = "abc123dfdf123c789";
            string pattern = @"(?<=3).+(?=1)"; //匹配在1的前面,3的后面,中间可以包含任意字符串
            MatchCollection mc = Regex.Matches(str, pattern);
            foreach(Match m in mc)
            {
                Console.WriteLine(m);
            }*/

学习了断言后,我们就可以利用断言来匹配上次图书管理系统出现的图书路径,可以更加简洁的把图书名称给匹配出来,共有三种方式: 1.第一种:采用断言方式

//1.采用断言方式匹配
            string[] bookNames = Directory.GetFiles("./");
            string pattern = @"(?<=\./).+(?=\.txt)"; // ./开头,.txt结尾 \是转义,取消/的作用
            foreach (string s in bookNames)
            {
                MatchCollection mc = Regex.Matches(s, pattern);
                foreach (Match m in mc)
                {
                    if (m.Success) //m.Success匹配成功在打印
                    {
                        Console.WriteLine(m);
                    }
                   
                }

            }
            

2.第二种方式:使用()去匹配我们要的子串:

    string pattern = @"./(.+)\.txt$";
            string[] files = Directory.GetFiles("./");
            foreach (string i in files)
            {
                Match m = Regex.Match(i, pattern);
                if (m.Success)
                {
                    Console.WriteLine(m.Groups[0]); //下标0拿到的是我们要匹配的子串
                    //现在我想拿到括号中的字符串
                    Console.WriteLine(m.Groups[1]); //下标1拿到的是第一个括号中匹配到的内容
                    Console.WriteLine(m.Groups[2]); //下标2拿到的是第二个括号中匹配到的内容
                }

            }

image.png 3.第三种方式:(?<占位符>正则*?):

    string pattern = @"\./(?<fileName>.+).txt"; //匹配左边是./,右边是.txt而且.txt必须是结尾
            string[] files = Directory.GetFiles("./");
            foreach (string s in files)
            {
                Match m = Regex.Match(s, pattern);
                if (m.Success)
                {
                    Console.WriteLine(m.Groups["fileName"]); //通过占位符fileName拿到对应括号中的匹配的内容
                }
            }

image.png 分析:提前在<>中定义好一个变量名,匹配成功后可以将占位符里面的结果打印出来

11.匹配日期:

        while (true)
            {
                Console.WriteLine("请输入日期:");
                string date = Console.ReadLine();
                string pattern = @"^([0-2][0-9]{3})-([0][1-9]|[1][0-2])-([0][1-9]|[1-2][0-9]|[3][0-1])$";
                Match match = Regex.Match(date, pattern);
                if (match.Success)
                {
                //获取匹配之后的年月日
                    Console.WriteLine(match.Groups[1]); 
                    Console.WriteLine(match.Groups[2]);
                    Console.WriteLine(match.Groups[3]);
                }
            }

image.png