本来写了蛮多的,结果因为重启了一下机器导致写的东西都没了。

然后再回想之前写了什么,反而更像是把知识提炼了一番。

关于字符

字符什么的只要记住.net里面都用的Unicode编码就好。字符和数字之间转换用强制转换是最简单且高效的,

字符串是引用类型,存在与堆上,然而同一般的对象用newobj这个IL指令创建不同,字符串由ldstr指令创建。(load string)

关于字符串

字符串是不可变的,所有的String的方法都是创建一个新的字符串。

用+号去拼接字符串,会在堆上创建多个string对象,而堆上的对象考虑到垃圾回收就会影响性能,所以建议用StringBuilder去拼接。

字符串比较

虽然String提供了一堆比较方法,并且《CLR via C#》这本书的作者也推荐用这些比较,因为==和!=这种比较方式调用者并没有显式指出用什么规则来比较,而如果显示地指出以什么规则来比较,代码容易阅读和维护。

 var str1 = "字符串1";
var str2 = "字符串2";
bool result1= str1.Equals(str2, StringComparison.OrdinalIgnoreCase);//使用序号排列(就是说对本地语言文化不敏感),并忽略大小写来比较。
bool result2 = str1 == str2;//常用的比较

然而,于我而言,确实是==更加明了,这个就看个人了。这些用方法比较的时候确实在有些多语言文化的场景比较好用,然而对于一般场景,我个人认为==更好一点,起码我自己看起来更好阅读和理解。

以StringComparison.Ordinal规则比较的话,CLR会快速先比较字符数量,数量相同才继续比较单独字符。而如果执行语言文化敏感的话,即使数量不同也有可能相等,所以一开始就会比较单个字符,这样就很耗性能。

System.StringComparer类也能执行字符串比较,它适用于大量不同字符串反复执行同一种比较。

字符串留用

CLR可通过一个String对象共享多个完全一致的String内容,这样就减少了字符串数量,节省内存,这就是字符串留用。

在.NET 4.5中自然会在程序集加载时对代码中的字面量字符串进行字符串留用,然而之前的版本就需要手动了。

String.Intern方法就是字符串留用的方法,将字符串加入一个哈希表中,如果哈希表中有就不加入,没有就加入。

这样当然可以减少内存,因为以后只引用一个字符串对象。但是要明白留存字符串这个操作也是需要消耗性能的。所以具体情况具体分析,还是需要慎重使用字符串留存。

字符串池

对于所有的字面量字符串中,相同内容的字符串,实际上都是引用的字符串池中的一个字符串。这是在C#编译器编译的时候就已经弄好的。

高效率构造字符串——StringBuilder

StringBuilder从字面意义上就很好理解了,字符串拼接什么的就用它好了。可以认为里面就是一个字符数组。

然而要理解StringBuilder的以下概念

  • 最大容量(MaxCapacity)

    • 指定了字符串中的最大字符数。默认值是Int32.MaxValue(约20亿)。
    • 一般不用理会,除非是要限制一个字符串的最大字符数。
  • 容量(Capacity)
    • 前面说到,可以将StringBuilder里面认为是一个字符数组,那么容量就指定了当前字符数组的长度。
    • 为什么说是当前呢?因为如果字符串拼接后超过了这个容量值,那么容量就会自动*2,且用新容量来分配新数组,并将原始数组中的字符串复制到新数组中。随后原始数据被垃圾回收。
    • 所以看到这里你就应该很明白一点,用StringBuilder最好在开始的时候自己预估一个容量,最起码不要让他频繁扩容,要不然真是坑,还不如用String。
  • 字符数组
    • 也就是StringBuilder里面由Char结构构成的数组。
    • 它的长度用Length获得

一般用用Append和AppendFormat进行追加字符串,当然也有其它的操作,只要明白里面操作的是一个数组就好。

虽然本书还介绍了一些字符串格式化和解析字符串的方式,然而

字符串编码——字符和字节的相互转换

对于使用汉字的我们使用字符串的话用Unicode没什么影响,因为汉字就占两个字节,然而对于英文字符实际上仅仅用一个字节就够了,但是在Unicode中还是会占两个字节,其中一个字节用于表示这个英文字符,另一个字节干脆就是\0。

所以一些英文翻译啊什么的,或者一大段英文文章的传送,那么将这些Unicode字符串编码成压缩的字节数组传送起来更有效率。

通常也就是用System.IO.BinaryWriter或者System.IO.StreamWriter时,需要进行编码,相应的读取时也需要解码。

一般不指定一种编码方案,那么就默认为UTF-8。(可以简单理解为中文两个字节,英文一个字节)

还有一种常用编码方案是UTF-16,也就是中英文都是两个字节,也被称为Unicode编码。(对于汉字而言,其实用UTF-16编码,比UTF-8更快)

其它的编码方式就不说了,对于我们而言基本上都是坑。

当我们进行编码时尽量用Encoding.Unicode获取编码方案构造对象,而不是用System.Text.UnicodeEncoding这种。

因为前者如果之前有请求会直接返回上次请求的对象给你,不会为每个请求构造新的对象。

而后者每次都会在托管堆中创建新的对象,所以会对性能有所影响。然而在System.Text中的这些派生自Encoding的编码类有特殊的构造器可以在对无效序列解码时抛出异常,所以如果要保证安全性,防范无效输入那么用后面这种比较好。

获取了这些编码方案构造对象后就可以利用GetBytes和GetString来将字符串转换为字节数组和将字节数组转换为字符串。

字节流的编码

就是通过System.Net.Sockets.NetworkStream对象读取一个UTF-16编码字符串,因为这种字节流通常以数据块形式传输,而如果一次从流中读取5个字节,而不是2的倍数的字节数,那么就可能会造成数据损坏。

所以可以用Encoding.Unicode.GetDecoder()获取一个新的构造对象,这个对象含有GetChars和GetCharCount两个方法。调用GetChars时它会尽可能多的解码,如果解码数组的字节不足以完成一个字符时,那么剩余的字符会保存到这个Decoder内部,下次调用它时,此Decoder会利用之前剩余的字节,再加上传给它的字节数组来进行解码。从流中读取Decoder对象的作用很大。

相反的编码一样。

以下为简单的Decoder解码示例

string strTroy = "奇葩";
Byte[] bytesTroy = Encoding.Unicode.GetBytes(strTroy);//形成长度为4的字节数组
Byte[] b1 = { bytesTroy[], bytesTroy[], bytesTroy[] };//一个奇,半个葩
Byte[] b2 = { bytesTroy[] };//半个葩
//以上操作算是模拟了按数据块获取,接下来
var decoder = Encoding.Unicode.GetDecoder();
char[] result=new char[];//解码后的字符数组
var charindex = decoder.GetCharCount(b1, , b1.Length);//若解码b1能形成的字符个数
decoder.GetChars(b1,, b1.Length, result, , false);//第一个0为从b1第0个位置开始解码,第二个0是从result的第0个位置开始写入
decoder.GetChars(b2,, b2.Length, result, charindex, false);
Console.WriteLine(string.Join("",result));//奇葩

安全字符串

System.Security.SecureString类,就是一个更安全的字符串类。

构造这个类的对象后,会在内部分配一个非托管内存块,以避开垃圾回收器。

和String对象不同,SecureString对象在回收后加密字符串的内容将不再存在于内存中。

当然这样的字符串如果不是信用卡啊密码什么的就不需要,毕竟会有性能影响。

【C#进阶系列】14 字符、字符串和文本编码的更多相关文章

  1. [Clr via C#读书笔记]Cp14字符字符串和文本处理

    Cp14字符字符串和文本处理 字符 System.Char结构,2个字节的Unicode,提供了大量的静态方法:可以直接强制转换成数值: 字符串 使用最频繁的类型:不可变:引用类型,在堆上分配,但是使 ...

  2. <NET CLR via c# 第4版>笔记 第14章 字符,字符串和文本处理

    14.1 字符 三种数值类型与 Char 实例的相互转换: static void Main() { Char c; Int32 n; //方法一: 通过C#转型(强制类型转换)实现数字与字符的相互转 ...

  3. clr from c# 字符 ,字符串 和 文本处理

    1,字符----------在.net中,字符总是16位的Unicode代码值.每个字符都是一个System.Char结构(值类型)的一个实列. using System; public class ...

  4. .Net进阶系列(14)-异步多线程(async和await)(被替换)

    1.  方法名前只有async,但是方法中Task实例前没有await关键字,该方法和普通方法没有什么区别,但是会报一个警告. #region 情况一 /// <summary> /// ...

  5. C#进阶系列 ---- 《CLR via C#》

      [C#进阶系列]30 学习总结 [C#进阶系列]29 混合线程同步构造 [C#进阶系列]28 基元线程同步构造 [C#进阶系列]27 I/O限制的异步操作 [C#进阶系列]26 计算限制的异步操作 ...

  6. 《Python CookBook2》 第一章 文本 - 过滤字符串中不属于指定集合的字符 && 检查一个字符串是文本还是二进制

    过滤字符串中不属于指定集合的字符 任务: 给定一个需要保留的字符串的集合,构建一个过滤函数,并可将其应用于任何字符串s,函数返回一个s的拷贝,该拷贝只包含指定字符集合中的元素. 解决方案: impor ...

  7. 重温CLR(十) 字符、字符串和文本处理

    本章将介绍.net中处理字符和字符串的机制 字符 在.NET Framewole中,字符总是表示成16位Unicode代码值,这简化了国际化应用程序的开发. 每个字符都表示成System.Char结构 ...

  8. 13、如何拆分含有多种分隔符的字符串 14、如何判断字符串a是否以字符串b开头或结尾 15、如何调整字符串中文本的格式 16、如何将多个小字符串拼接成一个大的字符串

    13.如何拆分含有多种分隔符的字符串 import re s = "23:41:2314\1234#sdf\23;" print(re.split(r'[#:\;]+',s))   ...

  9. C#进阶系列——一步一步封装自己的HtmlHelper组件:BootstrapHelper(三:附源码)

    前言:之前的两篇封装了一些基础的表单组件,这篇继续来封装几个基于bootstrap的其他组件.和上篇不同的是,这篇的有几个组件需要某些js文件的支持. 本文原创地址:http://www.cnblog ...

随机推荐

  1. Spring-Context之八:一些依赖注入的小技巧

    Spring框架在依赖注入方面是非常灵活和强大的,多了解点一些注入的方式.方法,绝对能优化配置. idref idref属性可以传入一个bean的名称,虽然它是指向一个bean的引用,但是得到的是该b ...

  2. iOS ARC模式 内存管理

     1,测试一 ;i<;i++) { NSLog(@"i = %d",i); } 2,测试二 ;i<;i++) { NSLog(@"i = %d",i ...

  3. EF架构~二级域名中共享Session

    回到目录 对于一个有点规模的网站,都会有各个子网站,说是子网站,其实也都是独立的站点,一般通过二次域名来分开,如www.zzl.com,它可以有很多子网站,如image.zzl.com,file.zz ...

  4. java初学者应掌握的30个基本概念

    核心提示:OOP中唯一关系的是对象的接口是什么,就像计算机的销售商她不管电源内部结构 是怎样的,他只关系能否给你提供电就行了,也就是只要知道can or not而不是how and why. 基本概念 ...

  5. Mysql 事件(定时任务)

    mysql 创建任务(事件) 1.检查数据库事件是否开启,如果 event_scheduler 等于 NO表示开启 SELECT @@event_scheduler; SHOW VARIABLES L ...

  6. 每天一个linux命令(50):crontab命令

    前一天学习了 at 命令是针对仅运行一次的任务,循环运行的例行性计划任务,linux系统则是由 cron (crond) 这个系统服务来控制的.Linux 系统上面原本就有非常多的计划性工作,因此这个 ...

  7. localStorage使用

    localStorage使用 需要注意的是,HTML5本地存储只能存字符串,任何格式存储的时候都会被自动转为字符串,所以读取的时候,需要自己进行类型的转换. 支持的情况如上图,IE在8.0的时候就支持 ...

  8. Android入门(十一)SQLite CURD

    原文链接:http://www.orlion.ga/594/ 一.添加数据 SQLiteOpenHelper的getReadableDatabase()或getWritableDatabase()方法 ...

  9. 汇编程序的Hello world

    原文链接:http://www.orlion.ga/989/ 一.汇编程序的Hello world x86 AT&T: .data   msg:       .ascii "Hell ...

  10. 让Team Foundation Server/TFS自动记住用户名密码解决方案

    在使用Team Foundation Server(以下简称TFS) 的时候,在每次打开Visual Studio TFS时候,需要输入用户名和秘密,比较麻烦.现提供一种方法可以解决这个问题: 依次执 ...