字符串是日常编码中最常用的引用类型了,可能没有之一,加上字符串的不可变性、驻留性,很容易产生性能问题,因此必须全面了解一下。


01、字符与字符编码

1.1、字符Char

字符 char 表示为 Unicode字符,在C#中用 UTF-16 编码表示,占用2个字节(16位)大小,字面量用单引号''包裹。

char c = 'A';
Console.WriteLine(char.IsDigit('3'));
Console.WriteLine(char.IsNumber('1'));
Console.WriteLine(char.IsLetter('A'));
Console.WriteLine(char.IsLower('a'));
Console.WriteLine(char.IsUpper('A'));
Console.WriteLine(char.GetUnicodeCategory('A')); //获取字符分类
  • char 是值类型(结构体),以16位整数形式存储,char可隐式转换为int
  • 字符串可以看做是char序列(数组),字符串是引用类型。

string str = "Hello World";
Console.WriteLine(str[0]); //H
Console.WriteLine(str[10]); //d
Console.WriteLine(str[0].GetType().Name); //Char

1.2、字符集Unicode与字符编码

一般情况下字符串长度string.Length 就是可见的文本字符数量,但这并不绝对相等。大多数字符都是一个char组成,然而有些字符无法用一个char表示,如表情、不常用字符等,他们会用两个char(4个字节)来表示。

"a".Length.Dump();    //1
"".Length.Dump(); //2
"".Length.Dump(); //2
"".Length.Dump(); //1
"你好".Length.Dump(); //2
"臢".Length.Dump(); //1
$"{(int)'A':X4}".Dump(); //0041
//上面的dump() 是一个扩展方法,作用同Console.WritLine()

Unicode 是国际标准、通用字符集,涵盖了世界上几乎所有的文字、符号,可以满足跨平台、跨语言的文本信息编码。Unicode 有100W+个字符地址空间,地址范围是 0x0000 - 0x10FFFF,每个字符都有自己的编码,目前已分配了大约10W+个。通常使用“U+”后跟一个十六进制数来表示,例如字母A的Unicode码点是U+0041

Unicode 字符集中包含多个分类(平面):其中最常用的就是基本平面,大部分常用字符都在这里面。

  • 基本多文种平面(BMP,Basic Multilingual Plane):Unicode 的BMP区域几乎包含了所有常用的字符,如几十种主流语言,及30000+的汉字,BMP区域的字符都只需要1个char(2个字节)表示。
  • 辅助平面(SMP):包含其他不常使用的字符,如一些历史文字、音乐符号、数学符号和表情符号等。该区域大多用两个char(4个字节)表示一个符号。

Unicode 是一种字符集,而实际在计算机上存储时需要用一个确定的编码方案,常见的就是UTF-8、UTF-16、UTF32。

  • UTF-16:2个字节表示BMP中的字符,其他字符会需要4个字节,C#、Java语言内部就是使用的UTF-16来表示的字符串。
  • UTF-8:变长编码,使用1到4个字节来表示一个Unicode字符,在互联网使用广泛。特别是存储 ASCII 为主的内容时,变长编码可以显著节约存储空间。

ASCII 字符集只包含 128个 基础字符,涵盖键盘上的字母、数字、常用符号。Unicode 是包含 ASCII字符集的,最前面128 个字符就是。在UTF-8编码中 ASCII字符只需要1个字节。


02、String基础

字符串 string 是一个不可变(不可修改)的字符序列(数组),为引用类型,字面量用双引号""包裹。

string s1 = "sam";
string s2 = new string('1',5);//11111
Console.WriteLine(s2[0]); //像数组一样操作字符串中的字符
string s3 = "";
string s4 = string.Empty; //效果同上
//相等比较
object s1= "Hello".Substring(0,2);
object s2 = "Hello".Substring(0,2);
(s1==s2).Dump(); //False
(s1.Equals(s2)).Dump(); //True
  • 字符串是引用类型,因此可以用null表示,不过一般空字符建议用string.Empty(或"")表示。
  • 字符串可以当做 字符数组一样操作,只是不能修改。
  • 字符串的相等为值比较,只要字符序列相同即可。例外情况请是如果用object==比较,只会比较引用地址。

字符串在存储、转换为字节码时需指定编码,一般默认为 UTF-8,这是广泛使用的编码类型,更节省空间。

2.1、字符串常用API

属性 特点/说明
Length 字符串中字符数量
索引器[int index] 索引器,用索引获取字符,不可修改
方法 特点/说明
StartsWithEndsWith(String) 判断开头、结尾是否匹配,"Hello".StartsWith("He")
Equals(String) 比较字符串是否相同
IndexOf() 查找指定字符(串)的索引位置,从后往前查找 LastIndexOf
Insert(Int32, String) 指定位置插入字符串,️返回新字符串!
PadLeft(Int32) 指定字符宽度(数量)对齐,左侧填充,️返回新字符串!右侧填充 PadRight(Int32)
Remove(Int32, Int32) 删除指定位置、长度的字符,️返回新字符串!
Replace(String, String) 替换指定内容的字符(串),️返回新字符串!
Substring(Int32, Int32) 截取指定位置、长度的字符串,️返回新字符串!
ToLower()ToUpper() 返回小写、大写形式的字符串,️返回新字符串!
Trim() 裁剪掉前后空格,️返回新字符串!有多个配套方法 TrimEndTrimStart
Split(char) 按分隔符分割字符串为多个子串,比较常用,不过性能不好,建议用Span代替。
静态方法 特点/说明
Empty 获取一个空字符串(同""
Compare(String, String) 比较两个字符串,有很多重载,返回一个整数,0表示相同。
Concat (params string?[]) 连接多个字符串,返回一个新的字符串,有很多重载,是比较基础的字符串连接函数。
Equals(str, StringComparison) 比较字符串是否相同,可指定比较规则 StringComparison
Format(String, Object[]) 字符串格式化,远古时期常用的字符串格式化方式,现在多实用$插值
string Intern(String) 获取“内部”字符串,先检查字符串池中是否存在,有则返回其引用,没有则添加并返回
string? IsInterned(String) 判断是否在字符串池中,存在则返回其引用,没有则返回null
IsNullOrEmpty(String) 判断指定的字符串是否 null 、空字符""/String.Empty,返回bool
IsNullOrWhiteSpace(String) 判断指定的字符串是否 null 、空字符""/String.Empty、空格字符,返回bool
Join(Char, String[]) 用分隔符连接一个数组为一个字符串

2.2、字符串的不变性、驻留性

字符串是一种有一点点特别的引用类型,因为其不变性,所以在参数传递时有点像值类型。

  • 不变性:字符串一经创建,值不可变。对字符串的各种修改操作都会创建新的字符串对象,这一点要非常重视,应尽量避免,较少不必要的内存开销。
  • 驻留性:运行时将字符串值存储在“驻留池(字符串池)”中,相同值的字符串都复用同一地址。

不变性、驻留性 是.Net对string 的性能优化,提升字符串的处理性能。如下示例中,s1、s2字符串是同一个引用。

string s1 = "hello";
string s2 = "hello";
Console.WriteLine(s1 == s2); //True
Console.WriteLine(s1.Equals(s2)); //True
Console.WriteLine(Object.ReferenceEquals(s1,s2)); //True

当然不是所有字符串都会驻留,那样驻留池不就撑爆了吗!一般只有两种情况下字符串会被驻留:

  • 字面量的字符串,这在编译阶段就能确定的“字符串常量值”。相同值的字符串只会分配一次,后面的就会复用同一引用。
  • 通过 string.Intern(string) 方法主动添加驻留池。

string st1 = "123" + "abc";
string st2 = "123abc";
string st3 = st2.Substring(0,3);

看看上面代码生成的IL代码:

  • 常量的字符串"123" + "abc"连接被编译器优化了。
  • 常量字符串使用指令“ldstr”加载的到栈,该指令会先查看驻留池中是否已存在,如果已存在则直接返回已有字符串对象的地址,否则就加入。

驻留的字符串(字符串池)在托管堆上存储,大家共享,内部其实是一个哈希表,存储被驻留的字符串和其内存地址。驻留池生命周期同进程,并不受GC管理,因此无法被回收。因此需要注意:

  • lock锁不能用string,避免使用同一个锁(字符串引用)。
  • 避免创建字面量的大字符串,会常住内存无法释放,当然也不要滥用string.Intern(string) 方法。

2.3、字符串的查找、比较

string 的 比较字符串 是默认包含文化和区分大小写的顺序比较,C#内置的一个字符串比较规则(枚举)StringComparison,可设置比较规则。在很多内置方法中使用,包括 String.Equals、String.Compare、String.IndexOf 和 String.StartsWith等。

微软官方建议在使用上述字符串比较方法中明确指定 StringComparison 参数值,而不是默认的比较规则。

public enum StringComparison
{
CurrentCulture,
CurrentCultureIgnoreCase,
InvariantCulture,
InvariantCultureIgnoreCase,
Ordinal,
OrdinalIgnoreCase
}
void Main()
{
string.Equals("ABC","abc",StringComparison.Ordinal); //Fasle
string.Equals("ABC","abc",StringComparison.OrdinalIgnoreCase); //True
string.Compare("ABC","abc",StringComparison.Ordinal); //-32
string.Compare("ABC","abc",StringComparison.OrdinalIgnoreCase);//0
}
枚举值 说明
CurrentCulture 本地语言区域规则,适用于给用户显示的内容
CurrentCultureIgnoreCase 同上+忽略大小写
InvariantCulture 固定语言区域,适用于存储的数据
InvariantCultureIgnoreCase 同上+忽略大小写
Ordinal 二进制值顺序比较字符串,比较快
OrdinalIgnoreCase 同上+忽略大小写

如果单纯从性能角度考虑,考虑语言文化的字符串比较其实比较慢,来测试对比一下。测试代码:

string s1 = "hellohellohellohello";
string s2 = "helloHelloHelloHello"; public bool Equals() => s1.Equals(s2);//False public bool Equals_CurrentCulture() => s1.Equals(s2,StringComparison.CurrentCulture);//False
public bool Equals_CurrentCultureIgnoreCase() => s1.Equals(s2,StringComparison.CurrentCultureIgnoreCase);//True
public bool Equals_InvariantCulture() => s1.Equals(s2,StringComparison.InvariantCulture);//False
public bool Equals_InvariantCultureIgnoreCase() => s1.Equals(s2,StringComparison.InvariantCultureIgnoreCase);//True
public bool Equals_Ordinal() => s1.Equals(s2,StringComparison.Ordinal);//False
public bool Equals_OrdinalIgnoreCase() => s1.Equals(s2,StringComparison.OrdinalIgnoreCase);//True public bool Equals_Span() => s1.AsSpan() == s2.AsSpan();//False
  • 上面7个方法 分别测试了Equals的默认版本、及带参 StringComparison 的不同比较规则的性能。
  • 最后加了一个使用Span 的相等比较,更多关于Span的资料查看《高性能的Span、Memory》。

测结结论

  • Span最快,其次无参Equals()版本、Ordinal,他们都是只比较二进制值,不考虑文化信息。
  • 个人理解,如果不考虑一些比较特别的语言(如瑞典语、土耳其语、 阿塞拜疆语等),只是针对英文、中文的字符串,一般不用考虑文化语义。
  • Equals()默认是不考虑文化语义的字符值比较,但有些比较方法就不一定能了,比如StartsWithCompare 默认的是带文化语义的CurrentCulture规则,因此推荐主动配置 StringComparison 参数。

2.4、字符串转义\

转义字符:反斜杠“\”

转义序列 字符名称 Unicode 编码
\' 单引号 0x0027
\" 双引号 0x0022
\0 null 0x0000
\b Backspace 0x0008
\f 换页 0x000C
\n 换行 0x000A
\r 回车 0x000D
\t 水平制表符 0x0009


03、字符串连接的8种方式

字符串连接(组装)的使用是非常频繁的,.Net中提供了多种姿势来实现,各有特点。

连接方法 示例/说明
直接相加 "hello"+str,其实编译后为 string.Concat ("hello", str)
连接函数:String.Concat() 字符串相加一般就是被编译为调用String.Concat()方法,有很多重载,支持任意多个参数
集合连接函数:String.Join() 将(集合)参数连接为一个字符串,string.Join('-',1,2,3); //1-2-3
格式化:String.Format() 传统的字符串格式化手艺,string.Format("name:{0},age:{1}",str,18)
$ 字符串插值 用花括号{var}引用变量、表达式,强大、方便,$"Hello {name} !"
@逐字文本字面量 支持转义符号、换行符,常用于文件路径、多行字符:@$"C:\\Users\\{name}\\Downloads"
"""原始字符串字面量 C# 11,三个双冒号包围,支持多行文本的原始字面量。
StringBuilder 当处理大量字符串连接操作时,推荐使用StringBuilder,效果更优。

字面量字符串的相加会被编译器优化,直接合并为一个字符串。

var str1 = "Hello " + "world" + " !";
var str2 = DateTime.Now.Year + "年" + DateTime.Now.Month + "月"; //编译后的代码:
string str1 = "Hello world !";
string str2 = string.Concat (DateTime.Now.Year.ToString (), "年", DateTime.Now.Month.ToString (), "月");

3.1、字符串格式化 String.Format

String.Format 方法是早期比较常用的字符串组织方式,后来$字符串插值 问世后就逐步被打入冷宫了。

string.Format("{0}+{1} = {2}",1,2,3);  //1+2 = 3
string.Format("Hello {0},{0}","sam"); //Hello sam,sam
String.Format("It is now {0:yyyy-MM-dd} at {0:hh:mm:ss}", DateTime.Now); //It is now 2024-01-17 at 10:56:33
String.Format("买了{0}个桔子,共花了{1:C2}。", 4,25.445); //买了4个桔子,共花了¥25.45。

基本语法规则就是用 {index}来占位,在后面的参数中给出值。

  • 索引位置从0开始,必须连续递增,可以重复。
  • 索引的位置对应后面参数的顺序位置,必须对应,参数不能少(抛出异常),可以多。
  • 字符串格式规则参考后文《字符串格式总结》。

3.2、$字符串插值

字符串插值的格式:$"{<interpolationExpression>}",大括号中可以是一个变量,一个(简单)表达式语句,还支持设置格式。功能强大、使用方便,老人孩子都爱用!

  • {}字符转义,用两个{{}}即可,如果只有一边,则用单引号'{{',即输出为{
  • 使用三元运算符?表达式,用括号包起来即可,因为“:”在插值字符串中有特殊含义,即格式化。
  • 字符串格式规则参考后文《字符串格式总结》。
var name = "sam";
Console.WriteLine($"Hello {name}!"); //Hello sam!
Console.WriteLine($"日期:{DateTime.Now.AddDays(1):yyyy-MM-dd HH:mm:ss}"); //日期:2024-01-18 23:21:55!
Console.WriteLine($"ThreadID:{Environment.CurrentManagedThreadId:0000}"); //ThreadID:0001
Console.WriteLine($"Length:{name.Length}"); //Length:3
Console.WriteLine($"Length:{(name.Length>3?"OK":"Error")}"); //Length:Error

3.3、@字符串支持任意字符

@标记的字符串为字面量字符串 ,不需要使用转义字符了,可搭配$字符串插值使用。文件路径地址都会用到@,两个冒号表示一个冒号,@"a""b" ==a"b

var path= @"D:\GApp\LINQPad 8\x64";
var file = $@"D:\GApp\LINQPad 8\x64\{DateTime.Now:D}";
var maxText = @"Hi All:
第一行
换行
";

3.4、StringBuilder

StringBuilder 字符串修理工程师,顾名思义,就是专门用来组装字符串的,可以看做是一个可变长字符集合。适用于把很多字符串组装到一起的场景,避免了大量临时字符串对象的创建,可显著提升性能。

var sb = new StringBuilder(100);
sb.Append("sam");
sb[0] = 'F'; //Fam
sb.AppendLine("age");
sb.Append("age").Append(Environment.NewLine); //效果同上
sb.Insert(2,"---");
sb.Replace("age","Age"); var result = sb.ToString(); //获取结果
属性 特点/说明
Capacity 获取、设置字符容量(实际占用内存),默认16,当内容增多容量不足时,会自动扩容。
MaxCapacity 获取最大容量,20亿字符
Length 实际字符内容的长度,可赋值,设置0则清空已有字符内容,但并不影响 Capacity
Chars[Int32] 索引器,可获取、设置字符
方法 特点/说明
StringBuilder(Int32) 构造函数,参数指定初始容量capacity
Append(value) 追加字符,很多重载版本,类似还有AppendFormat、AppendJoin
AppendLine 追加字符后,再追加一个换行符
Insert (int index, value) 指定位置插入字符内容
Replace(Char, Char) 查找替换字符(字符串)内容,会替换所有找到的字符内容
ToString() 将 StringBuilder 输出为一个字符串,一般是StringBuilder的命运终点。
  • 各种Append方法都返回自身,可用来链式编程。
  • StringBuilder 默认容量为16,内部有一个char数组m_ChunkChars(缓冲区)来存储字符内容,如下StringBuilder构造函数源码
public StringBuilder()
{
m_MaxCapacity = int.MaxValue;
m_ChunkChars = new char[16];
}
  • 当不断追加字符串,容量不足会自动扩容,扩容的过程其实就是创建更大的字符数组(容量翻倍),把原来的值拷贝过来,这个过程会涉及数组对象创建、内存拷贝。

一般使用StringBuilder 建议尽量给一个合理的默认容量大小,尽量避免、减少频繁的扩容。


04、字符串格式化大全

字符串格式语法:{index/interpolationExpression [,alignment][:formatString]}

  • ,alignment可选,设置字符串的对齐长度,如果位数不够则空格补齐,正数部补左边,负数补右边。
  • :formatString指定格式规则。一次只能指定一个格式规则,可和,alignment共存。
//,alignment 示例
var name = "sam";
$"name:{name,6}."; //字符长度6,前面补齐空格 //name: sam.
$"name:{name,-6}."; //字符长度6,后面补齐空格 //name:sam .
"1123+1 = {(1223+1),6:#,#.##}"; //1123+1 = 1,224
string.Format("1123+1 = {0,6:#,#.##}",1223+1); //1123+1 = 1,224

4.1、数值格式

标准数值格式

数值格式 说明
E3/e3 科学计数法(指数),数字"3"为小数精度,$"{12345.2:E3}" //1.235E+004E+4表示10的4次方;如果是E-4则表示为小数(除以10的四次方) 1E-4 = 0.0001
F4 定点格式,小数精度为"4",位数不够后面补0,支持所有数值类型,$"{123.22F:F4}" //123.2200
G4 定点格式F+指数E的结合版,最多"4"个有效数字,超过就用科学计数法。"{123:G2}" //1.2E+02$"{123:G4}" //123
C3 货币格式(支持千分位),数字“3”为小数位数,$"{123.346:C2}" //¥123.35
P2 百分比格式,数字乘以100后转换为百分数,数字“2”为小数位数,$"{0.2:P2}" //20.00%
N6 数字格式化(支持千分位),小数位数为6,不够后面补0,$"{123:N6}" //123.000000
D6 整数定长格式,不够前面补0,只支持整数,$"{123:D6}" //000123
B 输出为二进制格式,仅支持整数+.Net8,精度为字符串位数,不够补0,$"{123:B}" //1111011
X/x 输出为十六进制格式,仅支持整数+,精度为字符串位数,不够补0,$"{12:X4}" //000C

自定义的数值格式

数值格式符号 说明
# 数字占位符,不强制占位,$"{123:#,###.##}" //123
0 数字(0)占位符,强制占位,不够补0。$"{123:0000.00}" //0123.00
. 小数点,
, 千分位,
, 倍数符号,也是逗号,在末尾、小数点前为倍数符号,除以1000,可多个。$"{12000:#,}" //12
% 百分数,乘一百+%,$"{0.2:00.00%}" //20.00%
E/e 指数(科学计数),$"{10.1234:0.00e0}" //1.01e1$"{0.01234:0.00e0}" //1.23e-2
\\ 转义字符,

热知识:小数格式化截断时都会四舍五入,(int)double 强转换是直接截断整数部分,相当于向下取整。

冷知识:土耳其文化中的小数点为“逗号”,而非“点”。

4.2、日期时间格式

日期格式-自定义 说明(DateTimeDateTimeOffset
yyyy 年份,yyyy //2024,yy //24
MM 2位数的月份,1个M就不会补0 了,3/4个M为月份名称。M //4,MM //04,MMM //4月,MMMM //四月
dd 2位数的日,3/4个d为星期。d //8,dd //08,ddd //周一,dddd //星期一
HH 2位数的小时(24小时制)
hh 2位数的小时(12小时制)
mm 2位数的分钟
ss 2位数的秒
f 为1/10秒单位,ff为1/100秒单位,以此类推,fff就表示毫秒
tt AM/PM 指示符
组合使用 以上可组合使用,可穿插任意字符,$"{DateTime.Now:yyyy年MM月dd日 HH:mm:ss}"
日期格式-简写 说明
D、d D长日期,d短日期,$"{DateTime.Now:D}" //2024年1月18日
F、f 完整日期/时间模式,F长时间,f短时间,$"{DateTime.Now:F}" //2024年1月18日 22:45:34
T、t T长时间,t短时间,$"{DateTime.Now:T}" //22:45:42
M/m 月日模式,$"{DateTime.Now:M}" //1月18日
Y/y 年月模式,$"{DateTime.Now:Y}" //2024年1月

4.3、其他格式

枚举格式 说明
G/g,F/f 枚举的字符串名称,其中F用于Flags,$"{UType.User:G}" //User
D/d 十进制枚举值,$"{UType.User:D}" //2
X/x 十六进制枚举值,$"{UType.User:X}" //00000002
其他 说明
IFormattable 自定义的格式化接口,使用自定义的 IFormatProvider 来实现格式化输出ToString()
NumberStyles 用于解析数字符串(Parse)时指定的解析格式
DateTimeStyles 同上,用于时间日期的解析

格式MSDN参考资料


06、高性能字符串实践

提高string处理性能的核心就是:尽量减少临时字符串对象的创建

  • 高频常用字符串(非字面量)可考虑主动驻留字符串,string.Intern(name)
  • 字符串的比较、查找,优先用Span,或者尽量使用无文化语义的比较StringComparison.Ordinal
  • 大量字符串连接使用StringBuilder,且尽量给定一个合适的容量大小,避免频繁的扩容。
  • 少量字符串连接用字符串插值即可,创建StringBuilder也是有成本的。
  • 如果有大量StringBuilder 的使用,可以考虑用StringBuilderCache,或池化StringBuilder。

6.1、比较字符串

  • 字符串查找、拆分字符串、解析字符串,推荐使用Span,参考《高性能的Span、Memory》。
  • 查找、比较字符串,尽量指定 StringComparisonOrdinalOrdinalIgnoreCase,采用无文化特征的比较性能更快。
string str1="a",str2 = "b";
//这种方式会产生新的字符串,不推荐
if(str1.ToLower() == str2.ToLower()){}
//推荐写法
if(string.Compare(str1, str2, true)==0){}
if(string.Equals(str1,str2,StringComparison.Ordinal)){}

6.2、字符串真的不能修改吗?

字符串其实也是可以修改的,当然是用非常规手段。

  • ref获取指定字符的引用地址(指针地址)。
static void Main(string[] args)
{
var str1 = "hello";
var str2 = "hello";
//修改第0位
ref var c1 = ref MemoryMarshal.GetReference<char>(str1);
c1 = 'H';
//修改第一位
ref var c2 = ref MemoryMarshal.GetReference<char>(str1.AsSpan(1));
c2 = 'E';
Console.WriteLine(str1);//输出:HEllo
Console.WriteLine(str2);//输出:HEllo
}
  • 直接使用指针修改字符值。
void Main()
{
var str1 = "hello";
var str2 = "hello";
unsafe
{
fixed (char* c = str2)
{
c[0] = 'H';
c[1] = 'E';
}
}
Console.WriteLine(str1); //HEllo
Console.WriteLine(str2); //HEllo
}

参考资料


️版权申明:版权所有@安木夕,本文内容仅供学习,欢迎指正、交流,转载请注明出处!原文编辑地址-语雀

C#.Net筑基-String字符串超全总结 [深度好文]的更多相关文章

  1. 【Redis】命令学习笔记——字符串(String)(23个超全字典版)

    Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合). 本篇基于redis 4.0.11版本,学习字符串( ...

  2. 超全面的.NET GDI+图形图像编程教程

    本篇主题内容是.NET GDI+图形图像编程系列的教程,不要被这个滚动条吓到,为了查找方便,我没有分开写,上面加了目录了,而且很多都是源码和图片~ (*^_^*) 本人也为了学习深刻,另一方面也是为了 ...

  3. 转帖: 一份超全超详细的 ADB 用法大全

    增加一句 连接 网易mumu模拟器的方法 adb  connect 127.0.0.1:7555 一份超全超详细的 ADB 用法大全 2016年08月28日 10:49:41 阅读数:35890 原文 ...

  4. 【Redis】命令学习笔记——哈希(hash)(15个超全字典版)

    本篇基于redis 4.0.11版本,学习哈希(hash)相关命令. hash 是一个string类型的field和value的映射表,特别适合用于存储对象. 序号 命令 描述 实例 返回 HSET ...

  5. 【Redis】命令学习笔记——键(key)(20个超全字典版)

    安装完redis和redis-desktop-manager后,开始学习命令啦!本篇基于redis 4.0.11版本,从对键(key)开始挖坑! 准备工作,使用db1(默认db0,由于之前练习用db0 ...

  6. 超全面的JavaWeb笔记day03<JS对象&函数>

    1.js的String对象(****) 2.js的Array对象 (****) 3.js的Date对象 (****) 获取当前的月 0-11,想要得到准确的月 +1 获取星期时候,星期日是 0 4.j ...

  7. [转]超全面的.NET GDI+图形图像编程教程

    本篇主题内容是.NET GDI+图形图像编程系列的教程,不要被这个滚动条吓到,为了查找方便,我没有分开写,上面加了目录了,而且很多都是源码和图片~ GDI+绘图基础 编写图形程序时需要使用GDI(Gr ...

  8. 超全的web开发工具和资源

    首页 新闻 产品 地图 动态 城市 帮助 论坛 关于 登录 注册 · 不忘初心,继续前进,环境云V2接口正式上线 · 环境云测点地图全新改版 · 祝福各位环境云用户中秋快乐!   平台信息 培训互动 ...

  9. C++ 判断字符串是否全是数字

    在实际的工作中,需要提取程序中的字符串信息,但是程序中经常将一些数字当做字符串来进行处理,例如表盘的刻度信息,这时候就需要判断字符串是否全为数字,来进行真正意义上的字符串提取.下面介绍了判断字符串是否 ...

  10. JAVA----编程列出一个字符串的全字符组合情况,原始字符串中没有重复字符

    package com.pb.demo.packclass.demo1; import java.util.HashSet; /** * 编程列出一个字符串的全字符组合情况,原始字符串中没有重复字符 ...

随机推荐

  1. NOI 2024省选OIFC模拟21 蒲巴巴 超繁做法

    题目描述 一年一度的 PuBaBa 杯开始了! 今年的 PuBaBa 杯总共有 \(n\) 个选手来参加,编号分别为 \(1,2,\cdots,n\),他们的水平按编号依次递增,所以他们过的题目数量单 ...

  2. 【开通指南】 实时计算 Flink 全托管版本

    简介: [开通指南]实时计算 Flink 全托管版本 1.试用的实时计算 Flink 版产品是后付费还是预付费?是否有额外费用产生?预付费,有额外的SLB费用,一天2元封顶.(开通 Flink 全托管 ...

  3. 一文说清linux system load

    ​简介:双十一压测过程中,常见的问题之一就是load 飙高,通常这个时候业务上都有受影响,比如服务rt飙高,比如机器无法登录,比如机器上执行命令hang住等等.本文就来说说,什么是load,load是 ...

  4. PyFlink 教程(三):PyFlink DataStream API - state & timer

    简介: 介绍如何在 Python DataStream API 中使用 state & timer 功能. 一.背景 Flink 1.13 已于近期正式发布,超过 200 名贡献者参与了 Fl ...

  5. Dubbo3.0|阿里巴巴服务框架三位一体的选择与实践

    ​简介: 服务框架就像铁路的铁轨一样,是互通的基础,只有解决了服务框架的互通,才有可能完成更高层的业务互通,所以用相同的标准统一,合二为一并共建新一代的服务框架是必然趋势.Dubbo3.0 是 Dub ...

  6. [GPT] 对于一个复杂的html文档而言,如何用 js 批量替换页面上的某些文字从A替换为B,前提是不能去掉标签和已绑定的事件

      原生:示例代码 function replaceTextInDocument(node) { if (node.nodeType === Node.TEXT_NODE) { node.textCo ...

  7. PostMan测试图片上传接口的方法

    一.选择POST后添加接口地址 二.选择Body下的from-data 注:Headers不要加参数 三.填写key,再key后的下拉选择file,然后选择文件 注:key并不是图片名称,而是接口接收 ...

  8. fastreport .net打印普通报表

    fastreport .net打印普通报表 前言: .net代码层先不记录在这,后续会单独写一篇博客来记录. 直接在工具上进行功能点的实现 一.效果图 二.功能点 分页 分页小计 金额大写 三.功能点 ...

  9. CPU是什么?

    在程序是怎样跑起来的这本书中我们首先被询问的一个问题是"程序是什么?它是有什么组成的?而CPU又与程序有什么关系呢?",若我们能知道前两个,其实更容易将你带入讨论"CPU ...

  10. SpringBoot 二维码生成

    一.基于Google开发工具包ZXing生成二维码 1.引入需要的依赖 <!-- zxing生成二维码 --> <dependency> <groupId>com. ...