55

I don't see Dart strings treated as lists of characters. I assume I have to use for loops, which would be lame.

Marcelo Glasberg
  • 29,013
  • 23
  • 109
  • 133
mcandre
  • 22,868
  • 20
  • 88
  • 147

8 Answers8

72

An alternative implementation (working with characters outside the basic multilingual plane):

"A string".runes.forEach((int rune) {
  var character=new String.fromCharCode(rune);
  print(character);
});
CedX
  • 3,854
  • 2
  • 36
  • 45
  • 8
    Starting with Dart 2.7.0, you can use the package `characters`: https://pub.dev/packages/characters. – CedX Dec 18 '19 at 13:27
  • BonusPoint:: getter codeUnits can also be used in place of runes as in:```"A string".codeUnits.forEach((int c) { var character=new String.fromCharCode(c); print(character); });``` – lordvidex Apr 02 '20 at 01:24
  • 2
    `String.codeUnits` only deals with UTF-16 code points, whereas `String.runes` deals with Unicode code points (UTF-8, UTF-16, UTF-32). A character can be represented by 2 UTF-16 code points (i.e. a surrogate pair), but will be represented by only 1 rune. – CedX Jun 11 '20 at 16:45
  • @CedX Almost. As the name implies, `String.codeUnits` deals with UTF-16 code *units*; a code *unit* is an encoded portion of a Unicode code *point*. https://en.wikipedia.org/wiki/Character_encoding#Terminology – jamesdlin Mar 15 '23 at 18:26
37

You could also use the split method to generate a List of characters.

input.split('').forEach((ch) => print(ch));
Evin1_
  • 12,292
  • 9
  • 45
  • 47
34

Unfortunately strings are currently not iterable so you would have to use a for loop like this

for(int i=0; i<s.length; i++) {
  var char = s[i];
}

Note that Dart does not have a character class so string[index] will return another string.

Lars Tackmann
  • 20,275
  • 13
  • 66
  • 83
  • 6
    Warning: with some rare foreign languages, the loop does not work as expected. `length` property and `[]` operator refers to UTF-16 code units, not characters. Some characters can use 2 UTF-16 code units. – CedX Sep 18 '13 at 23:03
7

With Flutter Characters Class

import 'package:flutter/material.dart';
var characters = aString.characters;
Ryde
  • 654
  • 8
  • 23
  • 2
    The Flutter link is a re-export of [`package:characters/characters.dart`](https://pub.dev/documentation/characters/latest/) which can be used without Flutter too. It is the recommended way to iterate general Unicode text. – lrn Feb 23 '22 at 15:47
3

Extension to properly iterate a String:

extension on String {

  /// To iterate a [String]: `"Hello".iterable()`
  Iterable<String> iterable() sync* {
    for (var i = 0; i < length; i++) {
      yield this[i];
    }}}

Use it like this:

expect("Hello".iterable(), ["H", "e", "l", "l", "o"]);

However, if you add the Characters package:

import "package:characters/characters.dart"; 

Then you can have an extension to properly iterate a String using both simple characters or Unicode graphemes:

extension on String {

  /// To iterate a [String]: `"Hello".iterable()`
  /// This will use simple characters. If you want to use Unicode Grapheme
  /// from the [Characters] library, passa [chars] true.
  Iterable<String> iterable({bool unicode = false}) sync* {
    if (unicode) {
      var iterator = Characters(this).iterator;
      while (iterator.moveNext()) {
        yield iterator.current;
      }
    } else
      for (var i = 0; i < length; i++) {
        yield this[i];
      }
  }
}

To prove it works:

  test('String.iterable()', () {
    expect("Hello".iterable(), ["H", "e", "l", "l", "o"]);
    expect("Hello".iterable(unicode: true), ["H", "e", "l", "l", "o"]);

    expect("".iterable().length, 2);
    expect("".iterable().map((s) => s.codeUnitAt(0)), [55357, 56842]);

    expect("".iterable(unicode: true).length, 1);
    expect("".iterable(unicode: true), [""]);
  });
Marcelo Glasberg
  • 29,013
  • 23
  • 109
  • 133
2

extension on String {
  //toArray1 method
  List toArray1() {
    List items = [];
    for (var i = 0; i < this.length; i++) {
      items.add(this[i]);
    }
    return items;
  }

  //toArray2 method
  List toArray2() {
    List items = [];
    this.split("").forEach((item) => items.add(item));
    return items;
  }
}

main(List<String> args) {
  var str = "hello world hello world hello world hello world hello world";
  final stopwatch1 = Stopwatch()..start();
  print(str.toArray1());
  print('str.toArray1() executed in ${stopwatch1.elapsed}');

  final stopwatch2 = Stopwatch()..start();
  print(str.toArray2());
  print('str.toArray2() executed in ${stopwatch2.elapsed}');


}

The above is the example of using for loop and foreach but the result i tested, foreach is working way faster than for loop. Sorry if i was wrong, but it was my tests.

ke Chankrisna
  • 171
  • 3
  • 4
1

This also can be the solution : use it if you find it easy

String text = "findlastcharacter";
var array = text.split('');
array.forEach((element) { 
 print(element); // iterating char by char 
});
String lastchar = array[array.length - 1];
print('last char is = $lastchar'); // last char is = r

Thanks

0
import 'package:characters/characters.dart';  
      
String myString = "Hi";
for (var char in myString.characters) {
   print(char);
}
H
i

One thing to be aware of if you are starting with Characters is that they will be converted to String.

Characters myCharacters = "Hi.characters".characters;      
for (var char in myCharacters) {
        assert(char is String);
        print(char);
}
H
i
user3185563
  • 1,314
  • 2
  • 15
  • 22