String类
- 字符串的特性
String类用来比较两个字符串、查找和抽取串中的字符或子串。
string可以看做是char的只读数组。
C#中字符串有一个重要的特性:不可变性,字符串一旦声明就不再可以改变。
注意:对该类对象的任何操作都将返回一个新的字符串对象 除了Clone Clone直接将该字符串的引用返回了
示例:
String s1 = “a”;
String s2 = s1 + “b”;
Console.WriteLine(Object.ReferenceEquals (s1,s2));
谁说字符串不可变?string s = “abc”;s="123“;,s这不是变了吗
要区分变量名和变量指向的值的区别。程序中可以有很多字符串,然后由字符串变量指向他们,变量可以指向其他的字符串,但是字符串本身没有变化。字符串不可变性指的是内存中的字符串不可变,而不是变量不变。
string s10 = s;//s10指向s指向的字符串,而不是s10指向s,哪怕s以后指向了其他内存,那么s10还是指向从前s指向的字符串。
-
字符串的构造
String s = “abc”;
String s = new String(“fgh”.ToCharArray());
String copyS = String.Copy(s);
String newS = s.Clone() as String; -
字符串的遍历
字符串是一个字符数组
所以可以用遍历数组的方式遍历字符串的每一个位子的字符
示例:
```
String s1 = "123456";
for (int i=0;i<s1.Length;i++)
{
Console.WriteLine(s1[i]);
}
```
注意:
字符串中的字符位置和数组一样从下标0开始
字符串和数组一样有Length属性
字符串和数组一样可以按索引的方式访问
- 字符串的大小写转换
static void Task()
{
string str = "abcdefgh";
//将字符串中的小写字母转化成大写字母
str = str.ToUpper();
Console.WriteLine(str);
//将自服装中的大写字母转化成小写字母
str = str.ToLower();
Console.WriteLine(str);
}
- 字符串的截取
static void Task()
{
string no = "222023333";
//从某个位置开始截取 以直接截取到字符串的末尾
string retStr = no.Substring(5);
Console.WriteLine(retStr);
//从索引为0的位置开始截取5个长度的字符座位字符串返回
retStr = no.Substring(0,5);
Console.WriteLine(retStr);
}
//自己实现的方法:
static string MySubstring(string str, int startIndex, int len)
{
string retStr = string.Empty;
for (int i = startIndex; i < startIndex+len; i++)
{
retStr += str[i];
}
return retStr;
}
- 字符串的分割
static void Task()
{
string str = "I have a dream";
//剔除结果中的空字符
string[] strArr = str.Split(new char[] { ' '},StringSplitOptions.RemoveEmptyEntries);
Console.WriteLine(strArr.Length);
}
- 字符串的替换
static void Task()
{
string str = "TMD,你玩呢?";
//用"**"替换"TMD"
str = str.Replace("TMD","**");
Console.WriteLine(str);
}
- 字符串的查询
static void Task()
{
string str = "C#编程之道";
int index = str.IndexOf('编');
Console.WriteLine(index);
//返回从索引0开始搜索到第一个字符串为"编程"的第一个字符'编'的索引
index = str.IndexOf("编程");
Console.WriteLine(index);
//第一个字符串 表示目标字符串
//第二个参数表示 查找的开始位置的索引
//第三个参数表示 要检查的字符位置数
index = str.IndexOf("编程",2,2);
Console.WriteLine(index);
}
//自己实现
static int MyIndexOf(string str1,string str2)
{
if (str1.Length<str2.Length)
{
return -1;
}
for (int i = 0; i < str1.Length-str2.Length+1; i++)
{
string temp = str1.Substring(i, str2.Length);
if (temp==str2)
{
return i;
}
}
return -1;
}
- 字符串与ascii的转换
static void Task()
{
string str = "abcde";
byte[] byteArr = Encoding.ASCII.GetBytes(str);
for (int i = 0; i < byteArr.Length; i++)
{
Console.Write(byteArr[i] +" ");
}
string retStr = Encoding.ASCII.GetString(byteArr);
Console.WriteLine(retStr);
}
- 字符串的格式化
static void Task()
{
string name ="张三";
int age = 19;
string str = string.Format("姓名:{0},年龄:{1}",name,age);
}
- 字符串比较
static void Task(string str1, string str2)
{
//字符串在比较的时候相同索引的字符相互比较
//如果字符串长度相等 所有的对应索引的字符也一样那么返回0 例如"bjd" 和 "bjd" 比较返回0
//如果字符串长度不相等 具有相同索引值的字符比较,如果发现第一个字符串中的某个字符比第二个字符串相同索引的字符的ASCII大值返回1 否则如果小就返回-1 否则继续比较下一个 如果比较到两者中长度比较短的字符串末尾还没有分出大小 那么长度小字符串比较小
//由于第二个字符串是第一个字符串的子串 第一个字符串比四第二个要长 所以返回1
Console.WriteLine(string.Compare("abcd", "abc"));
//返回0 所有的字符都一样 及相等返回0
Console.WriteLine(string.Compare("abcd", "abcd"));
//第一个字符串的第二个字符比第二个字符串的第二个字符的ASCII大所以返回1
Console.WriteLine(string.Compare("aec", "abcd"));
}
字符串比较的在早期博客中已经写过了,并且有程序优化过程及思路大家可以参考此博文字符串比较的逻辑
- 去除空格
static string MyTrim(string str)
{
str = " 张 三 ";
//剔除字符串前缀空格和后缀空格
str = str.Trim();
Console.WriteLine(str);
Console.WriteLine(str.Length);
str = " 张 三 ";
//剔除前缀空格
str = str.TrimStart();
Console.WriteLine(str.Length);
//剔除后缀空格
str = " 张 三 ";
str = str.TrimEnd();
Console.WriteLine(str.Length);
str = "*******张 ** 三*******";
str = str.Trim('*');
Console.WriteLine(str.Length);
}
自己实现的逻辑
static string MyTrim(string str)
{
string retStr = string.Empty;
int firstCh = -1;
int lastCh = -1;
for (int i = 0; i < str.Length; i++)
{
if (str[i]!=' ')
{
firstCh = i;
break;
}
}
for (int i = 0; i < str.Length; i++)
{
if (str[str.Length-1 - i] != ' ')
{
lastCh = str.Length - 1 - i;
break;
}
}
return str.Substring(firstCh,lastCh-firstCh+1);
}
StringBuilder学习
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StringBuilderDemo
{
class Program
{
static void Main(string[] args)
{
StringBuilder sb = new StringBuilder();
//由于StringBuilder的Append参数是一个object类型的,所以可以添加很多 任意类型的数据
//追加字符串
sb.Append("12");
//追加整型
sb.Append(12);
sb.Append(new Student());
//以某种格式追加字符串
sb.AppendFormat("{0}***{1}***{2}",12,13,45);
//在下标为0的位置插入字符串"YY"
sb.Insert(0, "YY");
//从索引为0的位置移除2个长度的字符串
sb.Remove(0,2);
//将字符串"1991"替换成字符串"1998"
sb.Replace("1991","1998");
Console.WriteLine(sb);
//从下标为4的位置开始找到长度为4的字符串中将字符串"19"替换成"2000"
sb.Replace("19","2000",4,4);
Console.WriteLine(sb);
//sb的容量
Console.WriteLine(sb.Capacity);
}
}
}
String和StringBuilder的区别
using System;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace string和StringBuilder的性能比较
{
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
string ret = string.Empty;
sw.Start();
for (int i = 0; i < 100000; i++)
{
ret += i;
}
sw.Stop();
Console.WriteLine("总时间是:{0}",sw.Elapsed);
}
}
}
上图为string进行100次拼接的时候耗时为:0.00064秒
上面的图为string进行100000次拼接时累计消耗的时间是22.57秒
using System;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace string和StringBuilder的性能比较
{
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
StringBuilder sb = new StringBuilder();
sw.Start();
for (int i = 0; i < 100000; i++)
{
sb.Append(i);
}
sw.Stop();
Console.WriteLine("总时间是:{0}",sw.Elapsed);
}
}
}
上图为StringBuilder进行100次拼接时的耗时:0.00090秒 相对来说不如string操作的快。
上图为StringBuilder进行100000次拼接时的结果是0.025秒,结果是明显优于string的100000次拼接的
总结
结果上面的图分析,我们在进行少量字符串的拼接的时候使用string来说比较优,但是我们在进行次数为万级的操作的时候我们可以所选用StringBuilder相对来说更优