Dart 字符串是一组 UTF-16 单元序列。字符串通过单引号或双引号创建。

外链

更多信息

https://www.dartcn.com/guides/libraries/library-tour#strings-and-regular-expressions

完整 API

有关完整的方法列表, 请参考 String API docs
另请参考 StringBuffer, Pattern, RegExp,Match 的 API 文档。

创建字符串

  1. // 第一种
  2. var s1 = 'abc';
  3. print(s1 is String); //true
  4. // 第二种
  5. String s2 = "abc";

使用连续三个单引号或双引号实现多行字符串对象的创建。

保留内在格式,如换行和缩进等,里面写什么就输出什么。

  1. void main() {
  2. print('开始');
  3. var s3 = '''
  4. jack
  5. go
  6. ''';
  7. print(s3);
  8. print('结束');
  9. }

image.png

  1. void main() {
  2. print('开始');
  3. var s4 = """hello
  4. jack
  5. book
  6. go
  7. world""";
  8. print(s4);
  9. print('结束');
  10. }

image.png

字符串的拼接

  1. // 第一种:直接拼接
  2. var s1 = 'a' 'b' "c"; //'abc'
  3. var s2 = 'a'
  4. 'b'
  5. "c"; //'abc'
  6. // 第二种: +
  7. var s3 = 'a' + 'b' + 'c'; //'abc'
  8. var b = 'b';
  9. var s4 = 'a' + b + 'c'; //'abc'
  10. // 第三种:${}
  11. var s5 = 'a${b}c'; //'abc'

要以代码方式生成字符串,可以使用 StringBuffer 。 在调用 toString() 之前, StringBuffer 不会生成新字符串对象。 writeAll() 的第二个参数为可选参数,用来指定分隔符, 本例中使用空格作为分隔符。

  1. var sb = StringBuffer();
  2. sb
  3. ..write('Use a StringBuffer for ')
  4. ..writeAll(['efficient', 'string', 'creation'], ' ')
  5. ..write('.');
  6. var fullString = sb.toString();
  7. print(fullString); // Use a StringBuffer for efficient string creation.

字符串只可以比较是否相同,不能比较大小

  1. var a = 'a';
  2. var b = 'a';
  3. print(a == b); //true
  4. print(a > b); //Error: The operator '>' isn't defined for the class 'String'.

属性

length

  1. var s1 = 'abc';
  2. print(s1.length); //3
  3. print(s1[0]); //a

isEmpty、isNotEmpty 是否为空、不为空

  1. var s1 = 'abc';
  2. print(s1.isEmpty); //false
  3. print(s1.isNotEmpty); //true
  4. print(('').isEmpty); //true
  5. print((' ').isEmpty); //false

codeUnits 获取一个字符串的所有 UTF-16 编码单元

类似于js的 charCodeAt

  1. print('hello'.codeUnits); //[104, 101, 108, 108, 111]
  2. console.log('hello'.charCodeAt(0)); //104

方法

字符串的查找

indexOf、lastIndexOf

  • 作用:往后或往前查找一个字符串在调用此方法的字符串中第一次出现出现位置
  • 参数:需要查找的字符串、开始查找的位置索引
  • 返回:查找成功的字符串第一个位置的索引,不成功返回 -1
  1. print('jacka'.indexOf('aaaa')); //-1
  2. print('jacka'.indexOf('a')); //1
  3. print('jacka'.lastIndexOf('a')); //4

第二个参数

  • indexOf 针对前 n 个字符
  • lastIndexOf 表示从该位置起向前查找
    1. print('jacka'.indexOf('a', 2)); //4
    2. print('jacka'.lastIndexOf('a', 2)); //1

contains、startsWith、endsWith

  • contains():返回布尔值,表示是否找到了参数字符串。
  • startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
  • endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
  1. print('jack'.contains('a')); //true
  2. print('jack'.contains('ab')); //false
  3. //contains() 能够使用正则表达式。
  4. print('hello33h'.contains(new RegExp(r'\d+')));
  5. print('hello'.startsWith('he')); //true
  6. print('hello'.endsWith('he')); //false

split、splitMapJoin 分割字符串

split(sep) 返回值为 List 集合。
splitMapJoin(sep, (match) => (bool), (nonMatch) => (bool))

  1. // split
  2. print('hello world'.split(' ')); //[hello, world]
  3. print('hello world'.split('')); //[h, e, l, l, o, , w, o, r, l, d]
  4. // s1.splitMapJoin(sep, (match) => (bool), (nonMatch) => (bool))
  5. var s1 = "b a,c";
  6. print(s1.split(",")); //['b a', 'c']
  7. //查询 “,” ,用onMatch的返回值替换 “,” ;用onNonMatch的返回值替换其他
  8. var s2 = s1.splitMapJoin(",", onMatch: (Match match) {
  9. return "a";
  10. }, onNonMatch: (String nonMatch) {
  11. return "b";
  12. });
  13. print(s2); //bab

substring 抽取

从原字符串取出子字符串并以新字符串的方式返回,不改变原字符串。

参数:开始位置、结束位置(不包含结束位置,可省略)
第一个参数是子字符串的开始位置,第二个参数是子字符串的结束位置(不含该位置)。

  1. print('hello'.substring(1, 3)); //el
  2. // 如果省略第二个参数,则表示子字符串一直到原字符串结束。
  3. print('hello'.substring(1)); //ello

toLowerCase、toUpperCase大小写

大小写转换,返回转换后的字符串。
toLowerCase 用于将一个字符串全部转为小写,toUpperCase 则是全部转为大写。

  1. print('Hello World'.toLowerCase()); //'hello world'
  2. print('Hello World'.toUpperCase()); //'HELLO WORLD'

trim、trimLeft、trimRight 去除空格

用于去除字符串两端的空格,返回一个新字符串,不改变原字符串。

  1. var str = ' hello ';
  2. print('开始${str.trim()}结束'); //开始hello结束
  3. print('开始${str.trimLeft()}结束'); //开始hello 结束
  4. print('开始${str.trimRight()}结束'); //开始 hello结束

padLeft、padRight 补全

补齐长度 剩余位使用指定字符串替换

  1. var str = 'abc';
  2. // 剩余2位,每位默认使用""补齐
  3. print('开始${str.padLeft(5)}结束'); //开始 abc结束
  4. print('开始${str.padRight(5)}结束'); //开始 abc结束
  5. // 剩余2位,每位 使用"1"补齐
  6. print(str.padLeft(5, '1')); //11abc
  7. print(str.padRight(5, '1')); //abc11
  8. // 剩余2位,每位 使用"11"补齐
  9. print(str.padLeft(5, '11')); //1111abc
  10. print(str.padRight(5, '11')); //abc1111
  11. // 如果指定长度小于原字符串长度,返回原字符串
  12. print(str.padLeft(2, '11')); //abc

compareTo 字符串先后比较

  1. var str = 'chq';
  2. print(str.compareTo('abc')); //1 在ascii码中 c > a
  3. print(str.compareTo('cej')); //1 在ascii码中 h > e
  4. print(str.compareTo('cia')); //-1 在ascii码中 h < i
  5. print(str.compareTo('chq')); //0

正则

replaceFirst、replaceAll、replaceRange 替换

  • replaceFirst(match, replaceStr, index) 替换第一个匹配到的。第3个参数为开始搜索的位置。
  • replaceFirstMapped(match, (Match match) => (replaceStr), index) 替换第一个匹配到的,第二个参数为函数,替换值为该函数的返回值。
  • replaceAll() 替换所有匹配到的。
  • replaceAllMapped() 替换所有匹配到的,第二个参数为函数,替换值为该函数的返回值。
  • replaceRange(start, end, replaceStr) 替换指定范围。含头不含尾 ```dart print(‘abcab’.replaceFirst(‘a’, ‘你’)); //你bcab print(‘abcab’.replaceFirst(‘a’, ‘你’, 2)); //abc你b print(‘abcab’.replaceFirstMapped(‘a’, (Match match) => ‘你’)); //你bcab print(‘abcab’.replaceFirstMapped(‘a’, (Match match) => ‘你’, 2)); //abc你b

print(‘abcab’.replaceAll(‘a’, ‘你’)); //你bc你b print(‘abcab’.replaceAllMapped(‘a’, (Match match) => ‘你’)); //你bc你b

print(‘abcab’.replaceRange(1, 3, ‘你’)); //a你ab 把 1-3位 合起来替换为 你

  1. <a name="471c6474"></a>
  2. ### hasMatch 检测是否符合正则匹配,类似于js的 test
  3. ```dart
  4. var reg = new RegExp('a');
  5. print(reg.hasMatch('abc')); //true
  6. var str = '15903620494';
  7. var reg = RegExp(r'1[0-9]\d{9}$');
  8. print(reg.hasMatch(str)); //true

String、StringBuffer与StringBuilder之间区别

String StringBuffer StringBuilder
String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量优先的内存空间 StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量 可变类,速度更快
不可变 可变 可变
线程安全 线程不安全
多线程操作字符串 单线程操作字符串

简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,这样不仅效率低下,而且大量浪费有限的内存空间,所以经常改变内容的字符串最好不要用 String 。因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。

我们来看一下这张对String操作时内存变化的图:
String - 图3
我们可以看到,初始String值为“hello”,然后在这个字符串后面加上新的字符串“world”,这个过程是需要重新在栈堆内存中开辟内存空间的,最终得到了“hello world”字符串也相应的需要开辟内存空间,这样短短的两个字符串,却需要开辟三次内存空间,不得不说这是对内存空间的极大浪费。为了应对经常性的字符串相关的操作,就需要使用Java提供的其他两个操作字符串的类——StringBuffer类和StringBuild类来对此种变化字符串进行处理。

StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安**

对字符串进行修改的时候,特别是字符串对象经常改变的情况下,需要使用 StringBuffer 和 StringBuilder 类。
和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象
StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。

由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。

三者的继承结构

String - 图4
**

三者的区别:

String - 图5

(1)字符修改上的区别(主要,见上面分析)
(2)初始化上的区别,String可以空赋值,后者不行,报错
①String

  1. String s = null;
  2. String s = abc”;

②StringBuffer

  1. StringBuffer s = null; //结果警告:Null pointer access: The variable result can only be null at this location
  2. StringBuffer s = new StringBuffer();//StringBuffer对象是一个空的对象
  3. StringBuffer s = new StringBuffer(“abc”);//创建带有内容的StringBuffer对象,对象的内容就是字符串”

小结:(1)如果要操作少量的数据用 String;
(2)多线程操作字符串缓冲区下操作大量数据 StringBuffer;
(3)单线程操作字符串缓冲区下操作大量数据 StringBuilder