keyMatch4 function

bool keyMatch4(
  1. String key1,
  2. String key2
)

KeyMatch4 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *. Besides what KeyMatch3 does, KeyMatch4 can also match repeated patterns:

"/parent/123/child/123" matches "/parent/{id}/child/{id}" "/parent/123/child/456" does not match "/parent/{id}/child/{id}" But KeyMatch3 will match both.

Attention: key1 cannot contain English commas.

Implementation

bool keyMatch4(String key1, String key2) {
  var regEx = RegExp('\\{[^/]+}');
  var m = regEx.allMatches(key2).toList();

  var t = key2.split(regEx);

  var tokens = <String>[];
  if (t.isNotEmpty) {
    var cnt = 0;
    while (cnt < t.length) {
      tokens.add(t[cnt]);
      if (cnt < m.length) {
        tokens.add(m[cnt].group(0)!);
      }
      cnt++;
    }
  }

  var off = 0;
  for (var token in tokens) {
    if (!regEx.hasMatch(token) && token.isNotEmpty) {
      while (off < key1.length && key1[off] != token[0]) {
        off++;
      }
      if (key1.length - (off + 1) < token.length) {
        return false;
      }
      if (key1.substring(off, off + token.length) != token) {
        return false;
      }
      key1 = key1.replaceFirst(token, ',');
    }
  }
  var values = key1.split(',');

  var i = 0;
  var params = <String, String>{};

  for (var token in tokens) {
    if (regEx.hasMatch(token)) {
      while (i < values.length && values[i] == '') {
        i++;
      }
      if (i == values.length) {
        return false;
      }
      if (params.containsKey(token)) {
        if (values[i] != params[token]) {
          return false;
        }
      } else {
        params[token] = values[i];
      }
      i++;
    }
  }

  return true;
}