shorter version of buffer write method (DRY)

37 views Asked by At

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
3

There are 3 answers

0
julemand101 On BEST ANSWER

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);
}
1
Tomtom On

You can use cascade notation to use the StringBuffer object, and writeAll syntax :


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()
    ..writeAll([
      'minutes: ',
      lyric.substring(openBracketIndex + 1, colonIndex),
      '\n',
      'seconds: ',
      lyric.substring(colonIndex + 1, dotIndex),
      '\n',
      'hundredths: ',
      lyric.substring(dotIndex + 1, endBracketIndex),
      '\n',
      'lyrics: ',
      lyric.substring(endBracketIndex + 1)]);
  
  print(buffer);
}

0
lrn On

While I'm not usually the first to recommend regular expressions, this looks like an eminent example of where you should use one: To parse a known fixed format and extract the parts.

And use writeln to add the newline.

final lineRE = RegExp(r"^\[(\d+):(\d+)\.(\d+)\](.*)$");

void main() {
  final lyric = '[00:12.34]Row, row, row your boat';
  var parts = lineRE.firstMatch(lyric)!;
  return (StringBuffer()
    ..writeln('minutes: ${parts[1]}')
    ..writeln('seconds: ${parts[2]}')
    ..writeln('hundredths: ${parts[3]}')
    ..write('lyrics: ${parts[4]}')
  ).toString();
}