match method

  1. @override
List<List<SeparatorMatch>> match(
  1. String password
)
override

Should return the matches for the password.

A synchronous matcher should return a list (usually of length 1) of lists of matches. An asynchronous matcher can return a list of futures that completes with a list of matches.

Implementation

@override
List<List<SeparatorMatch>> match(String password) {
  final List<SeparatorMatch> result = <SeparatorMatch>[];
  final List<MapEntry<String, int>> mostUsedSeparators = password
      .split('')
      .where(separators.contains)
      .fold(<String, int>{}, (Map<String, int> counts, String separator) {
        counts[separator] = (counts[separator] ?? 0) + 1;
        return counts;
      })
      .entries
      .toList()
    ..sort(
      (MapEntry<String, int> a, MapEntry<String, int> b) =>
          b.value.compareTo(a.value),
    );
  // If the special character is only used once, don't treat it like
  // a separator.
  if (mostUsedSeparators.isEmpty || mostUsedSeparators[0].value < 2) {
    return <List<SeparatorMatch>>[result];
  }
  final String separator = mostUsedSeparators[0].key;
  final RegExp separatorRegExp =
      RegExp('([^$separator\n])($separator)(?!$separator)');
  for (final RegExpMatch match in separatorRegExp.allMatches(password)) {
    // Add one to the index because we changed the regex from negative
    // lookbehind to something simple. This simple approach uses the first
    // character before the separator too but we only need the index of the
    // separator.
    final int start = match.start + 1;
    result.add(
      SeparatorMatch(
        password: password,
        start: start,
        end: start + 1,
      ),
    );
  }
  return <List<SeparatorMatch>>[result];
}