normalizeNameLikeLineTitleCase function

String normalizeNameLikeLineTitleCase(
  1. String line
)

Applies title-case to all words in name-like lines.

This pass is intentionally narrow: only alphabetic lines with 2-4 tokens where at least one token already looks title-cased and at most one token is fully lowercase. This avoids changing normal sentence lines.

Implementation

String normalizeNameLikeLineTitleCase(String line) {
  if (line.isEmpty || RegExp(r'[^A-Za-z\s]').hasMatch(line)) {
    return line;
  }

  final List<String> tokens = line
      .split(RegExp(r'\s+'))
      .where((String token) => token.isNotEmpty)
      .toList();
  if (tokens.length < _nameLikeLineMinTokens ||
      tokens.length > _nameLikeLineMaxTokens) {
    return line;
  }

  int titleCaseTokens = 0;
  int lowercaseTokens = 0;
  int mixedCaseTokens = 0;
  for (final String token in tokens) {
    if (!isAlphaWord(token)) {
      return line;
    }

    if (isTitleCaseWord(token)) {
      titleCaseTokens++;
      continue;
    }

    if (token == token.toLowerCase()) {
      lowercaseTokens++;
      continue;
    }

    if (isMixedCase(token)) {
      mixedCaseTokens++;
      continue;
    }

    return line;
  }

  if (titleCaseTokens == 0 || lowercaseTokens > 1 || mixedCaseTokens > 1) {
    return line;
  }

  final List<String> normalized = <String>[];
  for (int i = 0; i < tokens.length; i++) {
    final String token = tokens[i];
    if (i > 0 &&
        token == token.toLowerCase() &&
        token.length <= _titleCasePreserveLowerTokenMaxLength) {
      normalized.add(token);
      continue;
    }

    if (isMixedCase(token) && _countUppercaseAfterStart(token) > 1) {
      normalized.add(token);
      continue;
    }

    final String repaired = _normalizeNameLikeToken(token);
    if (isMixedCase(token) && repaired == token) {
      normalized.add(token);
      continue;
    }

    normalized.add(toTitleCaseWord(repaired));
  }

  return normalized.join(' ');
}