dartstringbuffer

shorter version of buffer write method (DRY)


I have this method and I want to know is there a practical and clean way to write this code shorter: This excersice was from a Dart Apprentice: Beyond the Basics book.

void main() {
  final lyric = '[00:12.34]Row, row, row your boat';

  final openBracketIndex = lyric.indexOf('[');
  final colonIndex = lyric.indexOf(':');
  final dotIndex = lyric.indexOf('.');
  final endBracketIndex = lyric.indexOf(']');

  final buffer = StringBuffer();
  buffer.write('minutes: ');
  buffer.write(lyric.substring(openBracketIndex + 1, colonIndex));
  buffer.write('\n');

  buffer.write('seconds: ');
  buffer.write(lyric.substring(colonIndex + 1, dotIndex));
  buffer.write('\n');

  buffer.write('hundredths: ');
  buffer.write(lyric.substring(dotIndex + 1, endBracketIndex));
  buffer.write('\n');

  buffer.write('lyrics: ');
  buffer.write(lyric.substring(endBracketIndex + 1));
  print(buffer);
}

The output is:

minutes: 00
seconds: 12
hundredths: 34
lyrics: Row, row, row your boat

Solution

  • You can make use of the cascade notation and writeln method to shorten the code down to:

    void main() {
      final lyric = '[00:12.34]Row, row, row your boat';
    
      final openBracketIndex = lyric.indexOf('[');
      final colonIndex = lyric.indexOf(':');
      final dotIndex = lyric.indexOf('.');
      final endBracketIndex = lyric.indexOf(']');
    
      final buffer = StringBuffer()
        ..write('minutes: ')
        ..writeln(lyric.substring(openBracketIndex + 1, colonIndex))
        ..write('seconds: ')
        ..writeln(lyric.substring(colonIndex + 1, dotIndex))
        ..write('hundredths: ')
        ..writeln(lyric.substring(dotIndex + 1, endBracketIndex))
        ..write('lyrics: ')
        ..write(lyric.substring(endBracketIndex + 1));
    
      print(buffer);
    }
    

    We could also shorten it further if we allow us to build some of the string outside the StringBuilder:

    void main() {
      final lyric = '[00:12.34]Row, row, row your boat';
    
      final openBracketIndex = lyric.indexOf('[');
      final colonIndex = lyric.indexOf(':');
      final dotIndex = lyric.indexOf('.');
      final endBracketIndex = lyric.indexOf(']');
    
      final buffer = StringBuffer()
        ..writeln('minutes: ${lyric.substring(openBracketIndex + 1, colonIndex)}')
        ..writeln('seconds: ${lyric.substring(colonIndex + 1, dotIndex)}')
        ..writeln('hundredths: ${lyric.substring(dotIndex + 1, endBracketIndex)}')
        ..write('lyrics: ${lyric.substring(endBracketIndex + 1)}');
    
      print(buffer);
    }
    

    A less pretty solution would be to skip the StringBuffer and instead use a multi-line string as kind of a template:

    void main() {
      final lyric = '[00:12.34]Row, row, row your boat';
    
      final openBracketIndex = lyric.indexOf('[');
      final colonIndex = lyric.indexOf(':');
      final dotIndex = lyric.indexOf('.');
      final endBracketIndex = lyric.indexOf(']');
    
      final string = '''
    minutes: ${lyric.substring(openBracketIndex + 1, colonIndex)}
    seconds: ${lyric.substring(colonIndex + 1, dotIndex)}
    hundredths: ${lyric.substring(dotIndex + 1, endBracketIndex)}
    lyrics: ${lyric.substring(endBracketIndex + 1)}
    ''';
    
      print(string);
    }