42

I have a String, and I would like to reverse it. For example, I am writing an AngularDart filter that reverses a string. It's just for demonstration purposes, but it made me wonder how I would reverse a string.

Example:

Hello, world

should turn into:

dlrow ,olleH

I should also consider strings with Unicode characters. For example: 'Ame\u{301}lie'

What's an easy way to reverse a string, even if it has?

Seth Ladd
  • 112,095
  • 66
  • 196
  • 279
  • Can you please provide an example where this would be useful. There are now tons of answers that don't do the right thing for many inputs because you didn't specify a use-case with strict restrictions so that reversing a string worked. None of the answers so far work with simple inputs like `'Ame\u{301}lie'`. – Florian Loitsch Feb 03 '14 at 23:49
  • @FlorianLoitsch I was writing an Angular filter as a demonstration. It was simple to make a filter that reversed the string. I will clarify in the question what my use case was. – Seth Ladd Feb 04 '14 at 15:03

10 Answers10

99

The question is not well defined. Reversing arbitrary strings does not make sense and will lead to broken output. The first (surmountable) obstacle is Utf-16. Dart strings are encoded as Utf-16 and reversing just the code-units leads to invalid strings:

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

The split function explicitly warns against this problem (with an example):

Splitting with an empty string pattern ('') splits at UTF-16 code unit boundaries and not at rune boundaries[.]

There is an easy fix for this: instead of reversing the individual code-units one can reverse the runes:

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

But that's not all. Runes, too, can have a specific order. This second obstacle is much harder to solve. A simple example:

var input =  'Ame\u{301}lie'; // Amélie
print(new String.fromCharCodes(input.runes.toList().reversed)); // eiĺemA

Note that the accent is on the wrong character.

There are probably other languages that are even more sensitive to the order of individual runes.

If the input has severe restrictions (for example being Ascii, or Iso Latin 1) then reversing strings is technically possible. However, I haven't yet seen a single use-case where this operation made sense.

Using this question as example for showing that strings have List-like operations is not a good idea, either. Except for few use-cases, strings have to be treated with respect to a specific language, and with highly complex methods that have language-specific knowledge.

In particular native English speakers have to pay attention: strings can rarely be handled as if they were lists of single characters. In almost every other language this will lead to buggy programs. (And don't get me started on toLowerCase and toUpperCase ...).

Florian Loitsch
  • 7,698
  • 25
  • 30
  • 1
    I learned so much from this simple Q&A that now I'm wondering what's the matter with `toLowerCase` and `toUpperCase`. – André Mar 06 '18 at 03:18
  • @André I think he means about assuming all languages have an upper/lower case representation of their characters... like calling `toLowerCase` in an emoji UTF32 code, like `\u{1d11e} ` – Michel Feinstein Nov 26 '18 at 01:24
  • 2
    @mFeinstein It may also be referring to situations like the [Turkish İ problem](https://haacked.com/archive/2012/07/05/turkish-i-problem-and-why-you-should-care.aspx/) which lead to possibly broken comparisons depending on locale – Salem Jan 26 '19 at 15:15
  • 2
    Also Greek: a word like άσος should be ΑΣΟΣ (no diacritic) in all-caps, but Άσος (with diacritic) at the beginning of a sentence. – Lionel Rowe Mar 22 '19 at 05:44
  • 1
    For the record, Dart now provides `package:characters` which allows you to operate on strings at the *grapheme cluster* level, which is what you need to not break up accents and their characters, or change complicated emojis, or even just convert `"\r\n"` to `\n\r"`. Using the characters package, you can do `string.characters.toList().reversed.join("")` and not mangle composite characters. I still haven't found any real-world need for actually reversing a string, even if you do it correctly. And is it *really* correct if `""` does not become `""`? – lrn Jun 07 '22 at 12:22
22

Here's one way to reverse an ASCII String in Dart:

input.split('').reversed.join('');
  1. split the string on every character, creating an List
  2. generate an iterator that reverses a list
  3. join the list (creating a new string)

Note: this is not necessarily the fastest way to reverse a string. See other answers for alternatives.

Note: this does not properly handle all unicode strings.

Seth Ladd
  • 112,095
  • 66
  • 196
  • 279
  • This is not fast way because it create List. If you have string with big length it create to many strings. One string per each code unit in input string. This is not efficient way. – mezoni Feb 03 '14 at 15:38
  • Mezoni is right: his solution is simpler and faster. – Florian Loitsch Feb 03 '14 at 23:50
  • Thanks. I'll clarify that my answer is not intended to be the fastest way. – Seth Ladd Feb 04 '14 at 14:59
  • 1
    @FlorianLoitsch I tested 'Ame\u{301}lie' with the above and it was reversed. What are some strings where this fails? `print('Ame\u{301}lie'.split('').reversed.join(''));` ==> `eiĺemA` – Seth Ladd Feb 04 '14 at 15:10
  • 1
    That's not the correct inverse. The accent is on the "l" and not on the "e". Also: this is just an example where the runes need to be in order. If you have surrogate pairs it's even worse: "Music \u{1d11e} for the win". – Florian Loitsch Feb 04 '14 at 18:41
  • @FlorianLoitsch ah, thanks for catching that. Looking forward to your answer, so we get go on record for the proper way to reverse all strings. I know it's a artificial task, but it's teaching me more about strings. – Seth Ladd Feb 06 '14 at 14:57
12

I've made a small benchmark for a few different alternatives:

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));
}

Here is the result:

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)
ronag
  • 49,529
  • 25
  • 126
  • 221
2

Try this function

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));
}

(or)

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'));
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
Vignesh Kumar A
  • 27,863
  • 13
  • 63
  • 115
1

The library More Dart contains a light-weight wrapper around strings that makes them behave like an immutable list of characters:

import 'package:more/iterable.dart';

void main() {
  print(string('Hello World').reversed.join());
}
Lukas Renggli
  • 8,754
  • 23
  • 46
1

There is a utils package that covers this function. It has some more nice methods for operation on strings.

Install it with :

dependencies:
  basic_utils: ^1.2.0

Usage :

String reversed = StringUtils.reverse("helloworld");

Github:

https://github.com/Ephenodrom/Dart-Basic-Utils

Ephenodrom
  • 1,797
  • 2
  • 16
  • 28
1

Reversing "Hello World"

DiyorbekDev
  • 706
  • 1
  • 5
  • 19
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/32771355) – Augustas Sep 28 '22 at 05:46
  • https://meta.stackoverflow.com/a/285557/7733418 – Yunnosch Oct 05 '22 at 08:17
0

Here is a function you can use to reverse strings. It takes an string as input and will use a dart package called Characters to extract characters from the given string. Then we can reverse them and join again to make the reversed string.

String reverse(String string) {
  if (string.length < 2) {
    return string;
  }

  final characters = Characters(string);
  return characters.toList().reversed.join();
}
Amir_P
  • 8,322
  • 5
  • 43
  • 92
0

Create this extension:

extension Ex on String {
  String get reverse => split('').reversed.join();
}

Usage:

void main() {
  String string = 'Hello World';
  print(string.reverse); // dlroW olleH
}
CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
0

** Here is a function you can use to reverse strings. It takes an string as input and will use a dart package called split() to extract characters from the given string. Then we can reverse them and join again to make the reversed string. **

 String? stringReverse(String? string) {
      if (string != null) {
        final output = string.split('').reversed.join();
        return output;
      }
    }

    void main() {
      String? string = stdin.readLineSync();
      print(stringReverse(string));
    }