splitByAsciiWhitespacePreservingGroups function

List<String> splitByAsciiWhitespacePreservingGroups(
  1. String input
)

Split on ASCII whitespace, but do not split inside parentheses ()/[] or within single/double quotes.

Implementation

List<String> splitByAsciiWhitespacePreservingGroups(String input) {
  if (input.isEmpty) return const <String>[];

  final List<String> out = <String>[];
  final StringBuffer buf = StringBuffer();
  int parenDepth = 0;
  int bracketDepth = 0;
  String? quote;
  bool escape = false;

  void flush() {
    if (buf.isEmpty) return;
    final String token = buf.toString().trim();
    buf.clear();
    if (token.isNotEmpty) out.add(token);
  }

  for (int i = 0; i < input.length; i++) {
    final String ch = input[i];
    final int cu = input.codeUnitAt(i);

    if (quote != null) {
      buf.write(ch);
      if (escape) {
        escape = false;
      } else if (ch == '\\') {
        escape = true;
      } else if (ch == quote) {
        quote = null;
      }
      continue;
    }

    if (ch == '"' || ch == '\'') {
      quote = ch;
      buf.write(ch);
      continue;
    }

    if (ch == '(') {
      parenDepth++;
      buf.write(ch);
      continue;
    }
    if (ch == ')') {
      parenDepth = parenDepth > 0 ? parenDepth - 1 : 0;
      buf.write(ch);
      continue;
    }
    if (ch == '[') {
      bracketDepth++;
      buf.write(ch);
      continue;
    }
    if (ch == ']') {
      bracketDepth = bracketDepth > 0 ? bracketDepth - 1 : 0;
      buf.write(ch);
      continue;
    }

    if (parenDepth == 0 && bracketDepth == 0 && isAsciiWhitespaceCodeUnit(cu)) {
      flush();
      continue;
    }

    buf.write(ch);
  }

  flush();
  return out;
}