toSnakeCaseAcronyms method

  1. @useResult
String toSnakeCaseAcronyms()

Converts to snake_case, lowercasing acronyms (e.g. HTTPResponse → http_response).

Returns the snake_case string.

Example:

'HTTPResponse'.toSnakeCaseAcronyms();  // 'http_response'

Implementation

@useResult
String toSnakeCaseAcronyms() {
  if (isEmpty) return this;
  final StringBuffer sb = StringBuffer();
  for (int i = 0; i < length; i++) {
    final String c = this[i];
    if (c == ' ' || c == '-') {
      sb.write('_');
    } else {
      // Only cased uppercase letters start a word boundary. Checking that the
      // upper-cased form equals the character is not enough on its own, because
      // caseless characters such as digits and symbols also equal their own
      // upper-cased form. Also requiring the lower-cased form to differ excludes
      // those caseless characters.
      final bool upper = c.toUpperCase() == c && c.toLowerCase() != c;
      if (upper && i > 0) {
        final String prev = this[i - 1];
        final bool prevLower = prev.toUpperCase() != prev || prev.toLowerCase() == prev;
        final bool nextLower = i + 1 < length && this[i + 1].toLowerCase() == this[i + 1];
        // Insert "_" in two cases. First, a lower-then-Upper transition, e.g.
        // fooBar becomes foo_bar. Second, the last capital of an acronym that
        // begins a new word, detected by Upper-then-lower: in HTTPResponse the
        // boundary falls before the R, not inside the HTTP run.
        if (prevLower || (prev.toUpperCase() == prev && nextLower)) sb.write('_');
      }
      sb.write(c.toLowerCase());
    }
  }
  return sb.toString().replaceAll(RegExp(r'_+'), '_').replaceAll(RegExp(r'^_|_$'), '');
}