【C#进阶系列】14 字符、字符串和文本编码
本来写了蛮多的,结果因为重启了一下机器导致写的东西都没了。
然后再回想之前写了什么,反而更像是把知识提炼了一番。
关于字符
字符什么的只要记住.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 字符、字符串和文本编码的更多相关文章
- [Clr via C#读书笔记]Cp14字符字符串和文本处理
Cp14字符字符串和文本处理 字符 System.Char结构,2个字节的Unicode,提供了大量的静态方法:可以直接强制转换成数值: 字符串 使用最频繁的类型:不可变:引用类型,在堆上分配,但是使 ...
- <NET CLR via c# 第4版>笔记 第14章 字符,字符串和文本处理
14.1 字符 三种数值类型与 Char 实例的相互转换: static void Main() { Char c; Int32 n; //方法一: 通过C#转型(强制类型转换)实现数字与字符的相互转 ...
- clr from c# 字符 ,字符串 和 文本处理
1,字符----------在.net中,字符总是16位的Unicode代码值.每个字符都是一个System.Char结构(值类型)的一个实列. using System; public class ...
- .Net进阶系列(14)-异步多线程(async和await)(被替换)
1. 方法名前只有async,但是方法中Task实例前没有await关键字,该方法和普通方法没有什么区别,但是会报一个警告. #region 情况一 /// <summary> /// ...
- C#进阶系列 ---- 《CLR via C#》
[C#进阶系列]30 学习总结 [C#进阶系列]29 混合线程同步构造 [C#进阶系列]28 基元线程同步构造 [C#进阶系列]27 I/O限制的异步操作 [C#进阶系列]26 计算限制的异步操作 ...
- 《Python CookBook2》 第一章 文本 - 过滤字符串中不属于指定集合的字符 && 检查一个字符串是文本还是二进制
过滤字符串中不属于指定集合的字符 任务: 给定一个需要保留的字符串的集合,构建一个过滤函数,并可将其应用于任何字符串s,函数返回一个s的拷贝,该拷贝只包含指定字符集合中的元素. 解决方案: impor ...
- 重温CLR(十) 字符、字符串和文本处理
本章将介绍.net中处理字符和字符串的机制 字符 在.NET Framewole中,字符总是表示成16位Unicode代码值,这简化了国际化应用程序的开发. 每个字符都表示成System.Char结构 ...
- 13、如何拆分含有多种分隔符的字符串 14、如何判断字符串a是否以字符串b开头或结尾 15、如何调整字符串中文本的格式 16、如何将多个小字符串拼接成一个大的字符串
13.如何拆分含有多种分隔符的字符串 import re s = "23:41:2314\1234#sdf\23;" print(re.split(r'[#:\;]+',s)) ...
- C#进阶系列——一步一步封装自己的HtmlHelper组件:BootstrapHelper(三:附源码)
前言:之前的两篇封装了一些基础的表单组件,这篇继续来封装几个基于bootstrap的其他组件.和上篇不同的是,这篇的有几个组件需要某些js文件的支持. 本文原创地址:http://www.cnblog ...
随机推荐
- Java中测试异常的多种方式
使用JUnit来测试Java代码中的异常有很多种方式,你知道几种? 给定这样一个class. Person.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...
- php json与xml序列化/反序列化
在web开发中对象的序列化与反序列化经常使用,比较主流的有json格式与xml格式的序列化与反序列化,今天想写个jsop的小demo,结果发现不会使用php序列化,查了一下资料,做个笔记 简单数组js ...
- Bootstrap~大叔封装的弹层
回到目录 对于Bootstrap的弹层,插件有很多,今天主要用的是它自带的功能,通过bootstrap提供的模式窗口来实现的,而大叔主要对使用方法进行了封装,开发人员可以自己动态传入弹层的HTML内容 ...
- Java线程:线程的交互
一.线程交互的基础知识 SCJP所要求的线程交互知识点需要从java.lang.Object的类的三个方法来学习: void notify() 唤醒在此对象监视器上等 ...
- MyBatis学习总结(六)——调用存储过程
一.提出需求 查询得到男性或女性的数量, 如果传入的是0就女性否则是男性 二.准备数据库表和存储过程 1 create table p_user( 2 id int primary key auto_ ...
- Atitit jsr规范有多少个 407个。Jsr规范大全
Atitit jsr规范有多少个 407个.Jsr规范大全 1.1. JCP维护职能是发展和更新.1 1.2. Java技术规范.参考实现(RI).技术兼容包(TCK)1 1.3. JCP维护的规范 ...
- Atitit DbServiceV4qb9 数据库查询类库v4 新特性
Atitit DbServiceV4qb9 数据库查询类库v4 新特性 V4新特性 安全特性,屏蔽了executeUpdate,使用v2版 Sql异常转换,特别转换了DuplicateEnt ...
- 深度解析SDN——利益、战略、技术、实践(实战派专家力作,业内众多专家推荐)
深度解析SDN——利益.战略.技术.实践(实战派专家力作,业内众多专家推荐) 张卫峰 编 ISBN 978-7-121-21821-7 2013年11月出版 定价:59.00元 232页 16开 ...
- salesforce 零基础学习(三十一)关于LookUp字段点击Save时的Validation
今天在群里大概遇到了这样一个问题,明明这个User存在,但是save的时候提示信息说Value不存在,大概的意思如下图所示,目前认为这种问题常见的可能情况有两种. 一.此字段设置Validation ...
- Microsoft Visual Studio正忙解决办法
问题描述 前段时间用vs2015进行开发.出现如下问题,关闭vs进程重启vs还是无法解决. 如何解决 进入本地项目.vs文件夹 这个文件夹下有个.suo文件,删除该文件,用任务管理器杀掉vs的进程,重 ...