Created
October 12, 2024 13:17
-
-
Save Munawwar/4699d371a52b2040afd34fb7fcb8cc5d to your computer and use it in GitHub Desktop.
preact-iso's URL pattern matching algorithm in various languages
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Run program: go run preact-iso-url-pattern.go | |
package main | |
import ( | |
"fmt" | |
"regexp" | |
"strings" | |
) | |
func preactIsoUrlPatternMatch(urlStr, route string) bool { | |
url := filterEmpty(strings.Split(urlStr, "/")) | |
routeParts := filterEmpty(strings.Split(route, "/")) | |
for i := 0; i < max(len(url), len(routeParts)); i++ { | |
var m, param, flag string | |
if i < len(routeParts) { | |
re := regexp.MustCompile(`^(:?)(.*?)([+*?]?)$`) | |
matches := re.FindStringSubmatch(routeParts[i]) | |
if len(matches) > 3 { | |
m, param, flag = matches[1], matches[2], matches[3] | |
} | |
} | |
var val string | |
if i < len(url) { | |
val = url[i] | |
} | |
// segment match: | |
if m == "" && param == val { | |
continue | |
} | |
// /foo/* match | |
if m == "" && val != "" && flag == "*" { | |
break | |
} | |
// segment mismatch / missing required field: | |
if m == "" || (val == "" && flag != "?" && flag != "*") { | |
return false | |
} | |
rest := flag == "+" || flag == "*" | |
if rest { | |
break | |
} | |
} | |
return true | |
} | |
func filterEmpty(s []string) []string { | |
var result []string | |
for _, str := range s { | |
if str != "" { | |
result = append(result, str) | |
} | |
} | |
return result | |
} | |
func max(a, b int) int { | |
if a > b { | |
return a | |
} | |
return b | |
} | |
// Example usage: | |
func main() { | |
fmt.Println(preactIsoUrlPatternMatch("/foo/bar", "/foo/:param")) | |
fmt.Println(preactIsoUrlPatternMatch("/foo/bar/baz", "/foo/*")) | |
fmt.Println(preactIsoUrlPatternMatch("/foo", "/foo/:param?")) | |
fmt.Println(preactIsoUrlPatternMatch("/foo/bar", "/bar/:param")) | |
fmt.Println(preactIsoUrlPatternMatch("/users/test%40example.com/posts", "/users/:userId/posts")) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Run program: php preact-iso-url-pattern.php | |
function preactIsoUrlPatternMatch($url, $route) { | |
$url = array_filter(explode('/', $url)); | |
$route = array_filter(explode('/', $route ?? '')); | |
for ($i = 0; $i < max(count($url), count($route)); $i++) { | |
preg_match('/^(:?)(.*?)([+*?]?)$/', $route[$i] ?? '', $matches); | |
$m = $matches[1] ?? ''; | |
$param = $matches[2] ?? ''; | |
$flag = $matches[3] ?? ''; | |
$val = $url[$i] ?? null; | |
// segment match: | |
if (!$m && $param == $val) continue; | |
// /foo/* match | |
if (!$m && $val && $flag == '*') { | |
break; | |
} | |
// segment mismatch / missing required field: | |
if (!$m || (!$val && $flag != '?' && $flag != '*')) return false; | |
$rest = $flag == '+' || $flag == '*'; | |
if ($rest) break; | |
} | |
return true; | |
} | |
// Example usage: | |
var_dump(preactIsoUrlPatternMatch("/foo/bar", "/foo/:param")); | |
var_dump(preactIsoUrlPatternMatch("/foo/bar/baz", "/foo/*")); | |
var_dump(preactIsoUrlPatternMatch("/foo", "/foo/:param?")); | |
var_dump(preactIsoUrlPatternMatch("/foo/bar", "/bar/:param")); | |
var_dump(preactIsoUrlPatternMatch('/users/test%40example.com/posts', '/users/:userId/posts')); | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Run program: python3 preact-iso-url-pattern.py | |
def preact_iso_url_pattern_match(url, route): | |
url = list(filter(None, url.split('/'))) | |
route = list(filter(None, (route or '').split('/'))) | |
for i in range(max(len(url), len(route))): | |
m, param, flag = '', '', '' | |
if i < len(route): | |
parts = route[i].split(':') | |
m = ':' if len(parts) > 1 else '' | |
param = parts[-1] | |
flag = '' | |
if param and param[-1] in '+*?': | |
flag = param[-1] | |
param = param[:-1] | |
val = url[i] if i < len(url) else None | |
# segment match: | |
if not m and param == val: | |
continue | |
# /foo/* match | |
if not m and val and flag == '*': | |
break | |
# segment mismatch / missing required field: | |
if not m or (not val and flag != '?' and flag != '*'): | |
return False | |
rest = flag in ('+', '*') | |
if rest: | |
break | |
return True | |
# Example usage: | |
print(preact_iso_url_pattern_match("/foo/bar", "/foo/:param")) | |
print(preact_iso_url_pattern_match("/foo/bar/baz", "/foo/*")) | |
print(preact_iso_url_pattern_match("/foo", "/foo/:param?")) | |
print(preact_iso_url_pattern_match("/foo/bar", "/bar/:param")) | |
print(preact_iso_url_pattern_match('/users/test%40example.com/posts', '/users/:userId/posts')) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Run program: ruby preact-iso-url-pattern.rb | |
def preact_iso_url_pattern_match(url, route) | |
url = url.split('/').reject(&:empty?) | |
route = (route || '').split('/').reject(&:empty?) | |
(0...[url.length, route.length].max).each do |i| | |
m, param, flag = route[i]&.match(/^(:?)(.*?)([+*?]?)$/)&.captures || ['', '', ''] | |
val = url[i] | |
# segment match: | |
next if m.empty? && param == val | |
# /foo/* match | |
break if m.empty? && val && flag == '*' | |
# segment mismatch / missing required field: | |
return false if m.empty? || (!val && flag != '?' && flag != '*') | |
rest = flag == '+' || flag == '*' | |
break if rest | |
end | |
true | |
end | |
# Example usage: | |
puts preact_iso_url_pattern_match("/foo/bar", "/foo/:param") | |
puts preact_iso_url_pattern_match("/foo/bar/baz", "/foo/*") | |
puts preact_iso_url_pattern_match("/foo", "/foo/:param?") | |
puts preact_iso_url_pattern_match("/foo/bar", "/bar/:param") | |
puts preact_iso_url_pattern_match('/users/test%40example.com/posts', '/users/:userId/posts') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Run program: javac PreactIsoUrlPattern.java && java PreactIsoUrlPattern | |
import java.util.Arrays; | |
import java.util.List; | |
import java.util.regex.Matcher; | |
import java.util.regex.Pattern; | |
import java.util.stream.Collectors; | |
public class PreactIsoUrlPattern { | |
public static boolean match(String url, String route) { | |
List<String> urlParts = Arrays.stream(url.split("/")) | |
.filter(s -> !s.isEmpty()) | |
.collect(Collectors.toList()); | |
List<String> routeParts = Arrays.stream((route != null ? route : "").split("/")) | |
.filter(s -> !s.isEmpty()) | |
.collect(Collectors.toList()); | |
Pattern pattern = Pattern.compile("^(:?)(.*?)([+*?]?)$"); | |
for (int i = 0; i < Math.max(urlParts.size(), routeParts.size()); i++) { | |
String val = i < urlParts.size() ? urlParts.get(i) : null; | |
String routePart = i < routeParts.size() ? routeParts.get(i) : ""; | |
Matcher matcher = pattern.matcher(routePart); | |
String m = "", param = "", flag = ""; | |
if (matcher.find()) { | |
m = matcher.group(1); | |
param = matcher.group(2); | |
flag = matcher.group(3); | |
} | |
// segment match: | |
if (m.isEmpty() && param.equals(val)) continue; | |
// /foo/* match | |
if (m.isEmpty() && val != null && flag.equals("*")) { | |
break; | |
} | |
// segment mismatch / missing required field: | |
if (m.isEmpty() || (val == null && !flag.equals("?") && !flag.equals("*"))) return false; | |
boolean rest = flag.equals("+") || flag.equals("*"); | |
if (rest) break; | |
} | |
return true; | |
} | |
public static void main(String[] args) { | |
// Example usage | |
System.out.println(match("/foo/bar", "/foo/:param")); | |
System.out.println(match("/foo/bar/baz", "/foo/*")); | |
System.out.println(match("/foo", "/foo/:param?")); | |
System.out.println(match("/foo/bar", "/bar/:param")); | |
System.out.println(match("/users/test%40example.com/posts", "/users/:userId/posts")); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Run program: | |
// dotnet new console -n PreactIsoUrlPattern | |
// cd PreactIsoUrlPattern | |
// cp ../Program.cs . | |
// dotnet run | |
using System; | |
using System.Linq; | |
using System.Text.RegularExpressions; | |
class Program | |
{ | |
static bool preactIsoUrlPatternMatch(string url, string route) | |
{ | |
var urlParts = url.Split('/').Where(s => !string.IsNullOrEmpty(s)).ToArray(); | |
var routeParts = (route ?? "").Split('/').Where(s => !string.IsNullOrEmpty(s)).ToArray(); | |
for (int i = 0; i < Math.Max(urlParts.Length, routeParts.Length); i++) | |
{ | |
var match = Regex.Match(i < routeParts.Length ? routeParts[i] : "", @"^(:?)(.*?)([+*?]?)$"); | |
var m = match.Groups[1].Value; | |
var param = match.Groups[2].Value; | |
var flag = match.Groups[3].Value; | |
var val = i < urlParts.Length ? urlParts[i] : null; | |
// segment match: | |
if (string.IsNullOrEmpty(m) && param == val) continue; | |
// /foo/* match | |
if (string.IsNullOrEmpty(m) && val != null && flag == "*") | |
{ | |
break; | |
} | |
// segment mismatch / missing required field: | |
if (string.IsNullOrEmpty(m) || (val == null && flag != "?" && flag != "*")) return false; | |
bool rest = flag == "+" || flag == "*"; | |
if (rest) break; | |
} | |
return true; | |
} | |
static void Main(string[] args) | |
{ | |
Console.WriteLine(preactIsoUrlPatternMatch("/foo/bar", "/foo/:param")); | |
Console.WriteLine(preactIsoUrlPatternMatch("/foo/bar/baz", "/foo/*")); | |
Console.WriteLine(preactIsoUrlPatternMatch("/foo", "/foo/:param?")); | |
Console.WriteLine(preactIsoUrlPatternMatch("/foo/bar", "/bar/:param")); | |
Console.WriteLine(preactIsoUrlPatternMatch("/users/test%40example.com/posts", "/users/:userId/posts")); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment