如何在Dart中反转String?

Set*_*add 25 dart

我有一个字符串,我想扭转它.例如,我正在编写一个反转字符串的AngularDart过滤器.它仅用于演示目的,但它让我想知道如何反转字符串.

例:

Hello, world
Run Code Online (Sandbox Code Playgroud)

应该变成:

dlrow ,olleH
Run Code Online (Sandbox Code Playgroud)

我还应该考虑使用unicode字符的字符串.例如:'Ame\u{301}lie'

什么是反转字符串的简单方法,即使它有?

Flo*_*sch 49

问题没有明确定义.反转任意字符串没有意义,将导致输出中断.第一个(可克服的)障碍是Utf-16.Dart字符串被编码为Utf-16,并且仅反转代码单元导致无效字符串:

var input = "Music \u{1d11e} for the win"; // Music  for the win
print(input.split('').reversed.join()); // niw eht rof
Run Code Online (Sandbox Code Playgroud)

split函数明确警告这个问题(举个例子):

用空字符串模式('')拆分以UTF-16代码单元边界分割而不是符文边界[.]

有一个简单的解决方法:不是反转单个代码单元,而是可以反转符文:

var input = "Music \u{1d11e} for the win"; // Music  for the win
print(new String.fromCharCodes(input.runes.toList().reversed)); // niw eht rof  cisuM
Run Code Online (Sandbox Code Playgroud)

但那还不是全部.符文也可以有特定的顺序.这第二个障碍是很多难以解决的问题.一个简单的例子:

var input =  'Ame\u{301}lie'; // Ame?lie
print(new String.fromCharCodes(input.runes.toList().reversed)); // eil?emA
Run Code Online (Sandbox Code Playgroud)

请注意,重音是错误的字符.

可能还有其他语言对单个符文的顺序更敏感.

如果输入有严格的限制(例如Ascii或Iso Latin 1),则技术上可以反转字符串.但是,我还没有看到这个操作有意义的单个用例.

使用这个问题作为示例表明字符串具有类似List的操作也不是一个好主意.除少数用例外,必须根据特定语言处理字符串,并使用具有特定语言知识的高度复杂方法.

特别是母语为英语的人必须注意:字符串很少被处理,好像它们是单个字符列表一样.在几乎所有其他语言中,这将导致错误的程序.(不要让我开始toLowerCasetoUpperCase...).

  • @mFeinstein 它也可能指的是 [Turkish © 问题](https://haacked.com/archive/2012/07/05/turkish-i-problem-and-why-you-should-care.aspx /) 这可能会导致比较中断,具体取决于语言环境 (2认同)
  • 同样是希腊语:像 άσος 这样的词在全大写时应该是 ΑΣΟΣ(无变音符号),但在句子开头应该是 Άσος(带变音符号)。 (2认同)
  • 根据记录,Dart 现在提供了 `package:characters`,它允许您在 *grapheme cluster* 级别上操作字符串,这是您不需要分解重音及其字符,或更改复杂的表情符号,甚至只是转换`"\r\n"` 到 `\n\r"`。使用字符包,你可以执行 `string.characters.toList().reversed.join("")` 而不是 mangle 复合字符。我仍然即使你做得正确,也没有发现任何现实世界需要实际反转字符串。如果`""`没有变成`""`,它*真的*正确吗? (2认同)

Set*_*add 10

这是在Dart中反转ASCII字符串的一种方法:

input.split('').reversed.join('');
Run Code Online (Sandbox Code Playgroud)
  1. 在每个字符上拆分字符串,创建一个List
  2. 生成一个反转列表的迭代器
  3. 加入列表(创建一个新字符串)

注意:这不一定是反转字符串的最快方法.查看替代品的其他答案.

注意:这不能正确处理所有unicode字符串.


ron*_*nag 5

我为几种不同的选择做了一个小型基准测试:

String reverse0(String s) {
  return s.split('').reversed.join('');
}

String reverse1(String s) {
  var sb = new StringBuffer();
  for(var i = s.length - 1; i >= 0; --i) {
    sb.write(s[i]);
  }
  return sb.toString();
}

String reverse2(String s) {
  return new String.fromCharCodes(s.codeUnits.reversed);
}

String reverse3(String s) {
  var sb = new StringBuffer();
  for(var i = s.length - 1; i >= 0; --i) {
    sb.writeCharCode(s.codeUnitAt(i));
  }
  return sb.toString();
}

String reverse4(String s) {
  var sb = new StringBuffer();

  var i = s.length - 1;

  while (i >= 3) {
    sb.writeCharCode(s.codeUnitAt(i-0));
    sb.writeCharCode(s.codeUnitAt(i-1));
    sb.writeCharCode(s.codeUnitAt(i-2));
    sb.writeCharCode(s.codeUnitAt(i-3));
    i -= 4;
  }

  while (i >= 0) {
    sb.writeCharCode(s.codeUnitAt(i));
    i -= 1;
  }

  return sb.toString();
}

String reverse5(String s) {
  var length = s.length;
  var charCodes = new List(length);
  for(var index = 0; index < length; index++) {
    charCodes[index] = s.codeUnitAt(length - index - 1);
  }

  return new String.fromCharCodes(charCodes);
}
main() {
  var s = "Lorem Ipsum is simply dummy text of the printing and typesetting industry.";

  time('reverse0', () => reverse0(s));
  time('reverse1', () => reverse1(s));
  time('reverse2', () => reverse2(s));
  time('reverse3', () => reverse3(s));
  time('reverse4', () => reverse4(s));
  time('reverse5', () => reverse5(s));
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

reverse0: => 331,394 ops/sec (3 us) stdev(0.01363)
reverse1: => 346,822 ops/sec (3 us) stdev(0.00885)
reverse2: => 490,821 ops/sec (2 us) stdev(0.0338)
reverse3: => 873,636 ops/sec (1 us) stdev(0.03972)
reverse4: => 893,953 ops/sec (1 us) stdev(0.04089)
reverse5: => 2,624,282 ops/sec (0 us) stdev(0.11828)
Run Code Online (Sandbox Code Playgroud)