Как изменить строку в Dart?
У меня есть String, и я хотел бы отменить его. Например, я пишу фильтр AngularDart, который меняет строку. Это просто для демонстрационных целей, но это заставило меня задуматься о том, как изменить направление строки.
Пример:
Hello, world
должен превратиться в:
dlrow ,olleH
Я также должен рассматривать строки с символами Unicode. Например: 'Ame\u{301}lie'
Какой простой способ изменить строку, даже если она есть?
Ответы
Ответ 1
Вопрос не определен. Реверсирование произвольных строк не имеет смысла и приведет к нарушению вывода. Первым (преодолимым) препятствием является Утф-16. Строки Дарта кодируются как Utf-16, а реверсирование только кодовых единиц приводит к недопустимым строкам:
var input = "Music \u{1d11e} for the win"; // Music 𝄞 for the win
print(input.split('').reversed.join()); // niw eht rof
Функция 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
Но это не все. Руны тоже могут иметь определенный порядок. Это второе препятствие гораздо труднее решить. Простой пример:
var input = 'Ame\u{301}lie'; // Amélie
print(new String.fromCharCodes(input.runes.toList().reversed)); // eiĺemA
Обратите внимание, что акцент находится на неправильном символе.
Возможно, существуют и другие языки, которые еще более чувствительны к порядку отдельных рун.
Если ввод имеет серьезные ограничения (например, Ascii, или Iso Latin 1), то реверсивные строки технически возможны. Тем не менее, я еще не видел ни одного случая использования, когда эта операция имела смысл.
Использование этого вопроса в качестве примера для показа того, что строки имеют подобные List-операции, также не является хорошей идеей. За исключением нескольких случаев использования, строки должны обрабатываться по отношению к определенному языку и с очень сложными методами, которые имеют знание, специфичное для языка.
В частности, говорящие на родном английском языке должны обратить внимание: строки редко можно обрабатывать, как если бы они были списками отдельных символов. Практически на любом другом языке это приведет к ошибкам программ. (И не заставляйте меня начинать с toLowerCase
и toUpperCase
...).
Ответ 2
Здесь один из способов отменить строчку ASCII в дротике:
input.split('').reversed.join('');
- разделите строку на каждый символ, создав список
- сгенерировать итератор, который меняет список
- присоединиться к списку (создание новой строки)
Примечание: это не обязательно самый быстрый способ изменить строку. См. Другие ответы на альтернативы.
Примечание. Это неправильно обрабатывает все строки unicode.
Ответ 3
Я сделал небольшой ориентир для нескольких альтернатив:
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));
}
Вот результат:
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)
Ответ 4
Попробуйте эту функцию
String reverse(String s) {
var chars = s.splitChars();
var len = s.length - 1;
var i = 0;
while (i < len) {
var tmp = chars[i];
chars[i] = chars[len];
chars[len] = tmp;
i++;
len--;
}
return Strings.concatAll(chars);
}
void main() {
var s = "Hello , world";
print(s);
print(reverse(s));
}
(или)
String reverse(String s) {
StringBuffer sb=new StringBuffer();
for(int i=s.length-1;i>=0;i--) {
sb.add(s[i]);
}
return sb.toString();
}
main() {
print(reverse('Hello , world'));
}
Ответ 5
Библиотека Подробнее Dart содержит легкую обертку вокруг строк, которая заставляет их вести себя как неизменный список символов:
import 'package:more/iterable.dart';
void main() {
print(string('Hello World').reversed.join());
}