字符串string
主要是对string类的一些主要操作方法
static void Main(string[] args)
{
//使用string类型存储字符串类型,字符串用双引号引起来
string s = "www.baidu.com";
//Length属性
int sLength = s.Length;//Length返回字符串长度,就是获取该字符串有多少个字符,空格也属于一个字符
Console.WriteLine(sLength);
//比较字符串是否相等
string s1 = "www.baidu1.com1";
Console.WriteLine(s1 == s);//输出False
//字符串连接,直接使用+
s = "http://" + s;
Console.WriteLine(s);
//使用类似索引器访问字符串某个字符
Console.WriteLine(s[10]);
//遍历字符串所有字符
for(int i=0;i<s.Length;i++)
{
Console.WriteLine(s[i]);
}
//比较字符串,CompareTo,当两个字符串相同的时候,返回0 ,当s在字母表中靠前的时候,返回-1,否则返回1
int res = s.CompareTo("wwe");
Console.WriteLine(res);
//替换,Replase('.','-')把指定的字符换成指定的字符,或者把指定的字符串换成指定的字符串
Console.WriteLine(s);
string newStr = s.Replace('.', '-');
Console.WriteLine(newStr);
string newStr1 = s.Replace("www", "bbb");
Console.WriteLine(newStr1);
//split方法,切割
string[] strArray = s.Split('.');
foreach(string temp in strArray)
{
Console.WriteLine(temp);
}
//截取 Substring(index,length);//从索引index开始,截取length长度,如果length没有,就一直到结尾
string sSub = s.Substring(3, 7);
Console.WriteLine(sSub);
//ToUpper(),ToLower();Trim()//删除首尾空白
//IndexOf(string)//查找字符串,是否包含子字符串,并返回开始索引,不存在返回-1
Console.WriteLine(s.IndexOf("dev"));
Console.ReadKey();
}
StringBuilder
一、StringBuilder类是位于System.Text命名空间下
二、和string类的区别在于:string字符串是不可变的,string类型每次改变其实是创建了一个新的,然后复制过去,旧的就删除了;而StringBuilder 创建的字符串是可变的
三、所以如果对字符串会进行频繁的增加,删除等改变操作的时候,StringBuilder的效率会高很多,因为不会频繁的对内存进行操作
class Program
{
static void Main(string[] args)
{
//一、利用构造函数创建StringBuidler
StringBuilder sb = new StringBuilder("www.baidu.com");
//二、初始一个空StringBuilder对象,占有20个字符的大小
StringBuilder sb1 = new StringBuilder(20);
//三、初始化一个占有100个字符大小的字符串,并赋给一定的字符
StringBuilder sb2 = new StringBuilder("www.baidu.com", 100);
//Append(),添加
Console.WriteLine(sb2);
sb2.Append("/xxx.html");
Console.WriteLine(sb2);
//Insert(),在指定位置插入字符串
sb2.Insert(3, "wangzhipeng");
Console.WriteLine(sb2);
//Remove(index,length),表示从index开始移除length长度的字符串
sb2.Remove(3, 11);
Console.WriteLine(sb2);
//Replace,替换字符或者字符串
sb2.Replace('.', '-');
Console.WriteLine(sb2);
sb2.Replace("www", "abc");
Console.WriteLine(sb2);
Console.ReadKey();
}
}
正则表达式
正则表达式是当需要对字符串进行匹配操作的时候,比如说,匹配一段字符串是否是只有数字和字母;匹配一段字符串是否按照规定是指定的长度内存储的是指定的内容。
如果只判断字符串是不是都是数字,可以通过循环判断,但是对于复杂的字符串用循环判断就复杂了。这时候就用到正则表达式。
具体操作见代码:
class Program
{
static void Main(string[] args)
{
string s = "I am blue cat";
//搜索字符串,符合正则表达式的情况,然后把所有符合的位置替换成后面的字符串
//定位元字符,^ 定位开始位置
string newS = Regex.Replace(s, "^", "开始:");
Console.WriteLine(newS);
//定位元字符,$ 定位结束位置
string newS1 = Regex.Replace(s, "$", ":结束");
Console.WriteLine(newS1);
//校验密码是否都是数字
//string sCheck1 = Console.ReadLine();
string sCheck1 = "123123";
//方法一:for循环遍历,判断
bool isMatch = true;//默认标志位,表示是合法密码
for(int i=0;i<sCheck1.Length;i++)
{
if (sCheck1[i] < '0' || sCheck1[i] >'9')
{
isMatch = false;
break;
}
}
if (isMatch)
{
Console.WriteLine("合法密码");
}
else
{
Console.WriteLine("不合法密码");
}
//方法二:正则表达式
//元字符
//. 匹配除换行符以外的任意字符
//\w 匹配字母、数字、下划线、汉字 (指大小写字母、0-9的数字、下划线_)
//\W \w的补集 ( 除“大小写字母、0-9的数字、下划线_”之外)
//\s 匹配任意空白符 (包括换行符/n、回车符/r、制表符/t、垂直制表符/v、换页符/f)
//\S \s的补集 (除\s定义的字符之外)
//\d 匹配数字 (0-9数字)
//\D 表示\d的补集 (除0-9数字之外)
//在正则表达式中,\是转义字符. * 是元字符 如果要表示一个\ . *字符的话,需要使用\\ \. \*
isMatch = true;
string pattern = @"^\d*$";//正则表达式,表示规则是一个数字字符串
//^/d表示,以/d(数字0-9)开头,*表示一个或多个字符
isMatch = Regex.IsMatch(sCheck1, pattern);
if (isMatch)
{
Console.WriteLine("合法密码");
}
else
{
Console.WriteLine("不合法密码");
}
//反义字符
/*
\W \w的补集 ( 除“大小写字母、0 - 9的数字、下划线_”之外)
\S \s的补集(除\s定义的字符之外)
\D 表示\d的补集(除0 - 9数字之外)
\B 匹配不是单词开头或结束的位置
[ab] 匹配中括号中的字符
[a - c] a字符到c字符之间是字符
[^ x] 匹配除了x以外的任意字符
[^ adwz] 匹配除了adwz这几个字符以外的任意字符
*/
string strFan = "I am a cat.";
string patternStrFan = @"[^ahou]";
string afterFan = Regex.Replace(strFan, patternStrFan,"*");//把除了正则表达式内的字符,都转换成*
Console.WriteLine(afterFan);
//重复描述字符
/*
{n} 匹配前面的字符n次
{n,} 匹配前面的字符n次或多于n次
{n,m} 匹配前面的字符n到m次
? 重复零次或一次
+ 重复一次或更多次
* 重复零次或更多次
*/
string qq = "845294141";
string qq2 = "qq986995057";
string qq3 = "123123123123123";
string patternQQ = @"^\d{5,12}$";//重复\d5-12次
Console.WriteLine(Regex.IsMatch(qq, patternQQ));//IsMatch表示,只有有自字符合法就可以
Console.WriteLine(Regex.IsMatch(qq2, patternQQ));
Console.WriteLine(Regex.IsMatch(qq3, patternQQ));
//择一匹配
// | 将两个匹配条件进行逻辑“或”(Or)运算。
//输出字母和数字
string getOne = "34 ( ) asdf* 阿萨德价格";
string patternGetOne = @"\d|[a-z]";//表示/d或者[a-z]
MatchCollection col = Regex.Matches(getOne, patternGetOne);
foreach(Match match in col)
{
Console.WriteLine(match.ToString());
}
//输出人名
string name = "zhangsan;lisi,wangwu.zhaoliu";
string patternName = @"[;,.]";
string[] res = Regex.Split(name, patternName);
foreach(string temp in res)
{
Console.WriteLine(temp);
}
//使用择一匹配输出
string patternName1 = @"[;]|[,]|[.]";
string[] res1 = Regex.Split(name, patternName1);
foreach (string temp in res1)
{
Console.WriteLine(temp);
}
//重复多个字符使用(abcd){n}进行分组限定
string strInput = "abdfabdfab12ab__alksjdfabasdflj";
string strGroup = @"(ab\w{2}){2}";// == "ab\w{2}ab\w{2};
Console.WriteLine(Regex.Replace(strInput, strGroup,"5555"));
//检测IP地址是否合法
/*
* IP地址为:0-255.0-255.0-255.0-255
* 2 0-4 0-9 百位为2,十位0-4,个位0-9
* 2 5 0-5
* 0-1 0-9 0-9
* @"^(((
* 2[0-4]\d 2 0-4 0-9情况
* |
* 25[0-5] 2 5 0-5情况
* |
* [01]?\d\d?) ?表示前面的有零次或者1次,实现ip是二位或者一位树的运算
* \. 就表示.
* )
* {3} 实现***.***.***.三次
* (2[0-4]\d|25[0-5]|[01]?\d\d?))$
*/
string regexStrIp4 = @"^(((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?))$";
Console.WriteLine("请输入一个IP4地址:");
string inputStrIp4 = Console.ReadLine();
Console.WriteLine(inputStrIp4 + " 是否为合法的IP4地址:" + Regex.IsMatch(inputStrIp4, regexStrIp4));
Console.WriteLine("请输入一个IP4地址:");
string inputStrIp4Second = Console.ReadLine();
Console.WriteLine(inputStrIp4 + " 是否为合法的IP4地址:" + Regex.IsMatch(inputStrIp4Second, regexStrIp4));
Console.ReadKey();
}
}
委托
记录一中也有委托的相关概念,但仅仅是对委托赋一个方法名,进行引用,没有其他的操作。
这里会再介绍一些委托的方法,包括:
一、委托创建实例的两种方法:
1、通过new关键字
2、直接赋值
二、委托调用的两种方法:
1、变量后+括号
2、Invoke方法
三、委托作为参数进行传递
class Program
{
//定义一个委托类型,名字叫GetAString,返回值是string类型,参数为空
//编译器会把这个委托当作类处理
private delegate string GetAString();
static void Main(string[] args)
{
int x = 40;
string xTs = x.ToString();//ToString()用来把数据转换成字符串
Console.WriteLine(xTs);
//委托类型创建实例方法一:通过new关键字
//ToString没有带括号,只是把ToString引用一下
//a就指向了x.ToString方法
GetAString a = new GetAString(x.ToString);//引用类的普通方法
//委托类型实例调用方法一:直接变量后+括号
string xTs1 = a();
Console.WriteLine(xTs1);
//委托类型创建实例方法二:直接把方法赋值给委托类型变量
GetAString b = x.ToString;
//委托类型实例调用方法二:Invoke方法
string xTs2 = a.Invoke();
Console.WriteLine(xTs2);
//委托类型作为参数传递
PrintString method = Method1;//需要先初始化
PrintStr(method);
method = Method2;
PrintStr(method);
Console.ReadKey();
}
//委托类型做为参数传递
private delegate void PrintString();
static void PrintStr(PrintString print)
{
print();
}
static void Method1()//静态方法
{
Console.WriteLine("Method1");
}
static void Method2()
{
Console.WriteLine("Method2");
}
}
Action委托
除了我们自己定义委托之外,还可以调用系统自带的委托,下面介绍Action委托
//Action是系统内置(预定义)的委托类型
//Action只能指向没有返回值,参数可以有可以没有
//参数通过泛型控制Actiong<int,string,bool....>最多可以带有16个参数,参数类型必须对应
class Program
{
static void PrintStr()
{
Console.WriteLine("helloworld");
}
static void PrintInt(int num)
{
Console.WriteLine(num);
}
static void PrintInt(int num1,int num2)
{
Console.WriteLine(num1 + num2);
}
static void Main(string[] args)
{
//一、使用Action指向一个无参数,无返回值类型的方法
int x = 100;
Action a = PrintStr;
a();
//二、使用Action指向无返回值,有一个参数的方法
Action<int> b = PrintInt;
b(10);
//三、使用Action指向无返回值,多个参数的方法
//如果有重载方法,系统会自动匹配
Action<int, int> c = PrintInt;
c(10, 10);
Console.ReadKey();
}
}
Func委托
上面Action委托是没有返回值的自带的委托,当然也有必须要有返回值的委托,就是Func委托
参数依然是0-16个之间,参数类型也需要对应,在泛型里面,最后一个代表返回值类型,前面的都代表参数类型
class Program
{
static int Test1()
{
return 1;
}
static int Test2(string str)
{
return str.Length;
}
static int Test3(string str,int num)
{
return num + str.Length;
}
static void Main(string[] args)
{
//一、只有返回值类型,没有参数类型
Func<int> a = Test1;//泛型中指定的是返回值类型
Console.WriteLine(a());
//二、带有返回值类型和一个参数类型
Func<string, int> b = Test2;//泛型中,最有一个类型表示返回值类型,前面的表示参数类型
Console.WriteLine(b("ASDFASDFASDF"));
//三、带有int返回值类型和两个参数类型(string,int)
Func<string, int, int> c = Test3;
Console.WriteLine(c("asdf", 12));
Console.ReadKey();
}
}
多播委托
//多播委托,是委托指向多个方法
//添加什么顺序,调用就是什么顺序
//如果有返回值,返回的是最后一个委托的方法的结果
//当委托没有指向方法的时候就调用,会出现异常
//如果多播委托某个发生异常,整个过程停止。
class Program
{
static void Test1()
{
Console.WriteLine("test1");
}
static void Test2()
{
Console.WriteLine("test2");
}
static void Main(string[] args)
{
//多播委托,是委托指向多个方法
Action a = Test1;
//+委托
a += Test2;
a();
//-委托
a -= Test1;
a();
Console.WriteLine();
//取得多播委托中所有的方法的委托
a += Test2;
a += Test1;
Delegate[] delegates = a.GetInvocationList();
foreach(Delegate d in delegates)
{
d.DynamicInvoke();
}
Console.ReadKey();
}
}
匿名方法
//本质上还是方法,只是没有名字
//任何使用委托变量的地方,都可以使用匿名方法赋值
namespace 匿名方法
{
class Program
{
//Test1是有名字的方法
static int Test1(int a,int b)
{
return a + b;
}
static void Main(string[] args)
{
Func<int, int, int> plus = Test1;
//将上述修改成匿名方法的形式
Func<int, int, int> plus1 = delegate (int arg1, int arg2)
{
return arg1 + arg2;
};
//匿名方法只能赋值给委托去调用,不需要在其他地方调用
//一般用在回调函数中
Console.WriteLine(Test1(1, 2));
Console.ReadKey();
}
}
}
Lambda表达式
//Lambda就是用来替代匿名方法的,所以Lambda表达式也是定义方法
namespace Lambda表达式
{
class Program
{
static void Main(string[] args)
{
//下面是匿名方法
Func<int, int, int> plus = delegate (int arg1, int arg2)
{
return arg1 + arg2;
};
//用Lambda表达式表示,参数不需要声明类型
//=>左边列出参数,右边是函数体
Func<int, int, int> plus1 = (arg1, arg2)=>
{
return arg1 + arg2;
};
Console.WriteLine(plus1(1, 2));
//如果只有一个参数,不需要括号
Func<int, int> test2 = a => { return a; };
Console.WriteLine(test2(3));
//如果函数体只有一句,不需要大括号
Func<int, int> test3 = a => a + 1;
Console.WriteLine(test3(3));
//访问外部的变量
int somVal = 5;
Func<int, int> f = x => x + somVal;
Console.WriteLine(f(3));
somVal = 7;
Console.WriteLine(f(3));
Console.ReadKey();
}
}
}
事件
//事件只能作为类成员声明
//声明加上关键词event,基于委托,是一种特殊的委托,发布订阅机制
//使用和委托相似
//个人感觉:类似于QT中的信号和槽
namespace _011_事件
{
class Program
{
public delegate void MyDelegate();
public MyDelegate mydelegate;//声明委托类型变量作为类成员
public event MyDelegate myevent;//声明事件
static void Main(string[] args)
{
Program p = new Program();
p.mydelegate = Test1;
p.mydelegate();
p.myevent = Test1;
p.myevent();
Console.ReadKey();
}
static void Test1()
{
Console.WriteLine("Test1");
}
}
}
对事件的使用,观察者模式
//有一个被观察者:
//多个观察者:观察被观察者的状态变化
//当被观察者发生状态变化,观察者就会做相应的事情
//相当于QT中信号和槽的关系
//不要因为观察者的变化去修改被观察者里面的代码
首先有被观察者:Cat类
class Cat
{
private string name;
private string color;
public Cat(string name,string color)
{
this.name = name;
this.color = color;
}
/// <summary>
/// 猫进屋,(被观察者状态发生改变)
/// </summary>
public void CatComming(Mouse mouse1,Mouse mouse2)
{
Console.WriteLine(color + "猫" + name+"过来了,喵喵喵...");
mouse1.RunAway();
mouse2.RunAway();
}
public void CatEat()
{
Console.WriteLine(color + "猫" + name + "吃东西,喵喵喵...");
if(catEat!=null)
{
catEat();
}
}
public void CatCommingNow()
{
Console.WriteLine(color + "猫" + name + "过来了,喵喵喵...");
if(catCome !=null)
{
catCome();
}
}
public Action catCome;//声明一个委托,让观察者去注册,这个时候可以通过cat对象去调用,可能发生问题
public event Action catEat;//防止外接调用,加入event,事件不能在类的外部触发,只能在类内部触发,但可以在外部注册
}
然后再来一个观察者,mouse类
class Mouse
{
private string name;
private string color;
public Mouse(string name,string color,Cat cat)
{
this.name = name;
this.color = color;
cat.catCome += this.RunAway;//减少每次增加观察者都注册一下的操作
}
public void RunAway()
{
Console.WriteLine(color + "的老鼠" + name + "逃跑了...吱吱吱");
}
public void Happy()
{
Console.WriteLine(color + "的老鼠" + name + "很开心...吱吱吱");
}
}
观察者和被观察者结合
class Program
{
static void Main(string[] args)
{
Cat cat = new Cat("加菲猫", "黄色");
cat.catCome();//这是个委托,可以外部调用,但是很危险;最好改成事件
Mouse mouse1 = new Mouse("米奇", "黑色",cat);
// cat.catCome += mouse1.RunAway;比较繁琐,直接修改Mouse的构造函数,增加参数
Mouse mouse2 = new Mouse("唐老鸭", "红色",cat);
// cat.catCome += mouse1.RunAway;
//cat.CatComming(mouse1,mouse2);//猫的状态发生改变,发送一个消息,让观察者接收后决定动作
//上一行,在cat中调用了观察者的方法,当观察者发生改变的时候,要同时修改被观察者的代码,耦合性太高
cat.CatCommingNow();
Console.ReadKey();
}
}