URL Pattern API
注意:此功能在 Web Workers 中可用。
URL 模式 API 定义了一种用于创建 URL 模式匹配器的语法。这些模式可以与 URL 或单个 URL 组件进行匹配。
概念与用法
模式使用 URLPattern 接口指定。模式语法基于 path-to-regexp 库的语法。模式可以包含:
- 将被精确匹配的字面字符串。
- 匹配任何字符的通配符 (
/posts/*)。 - 提取匹配 URL 部分的命名组 (
/books/:id)。 - 使模式部分可选或多次匹配的非捕获组 (
/books{/old}?)。 RegExp组 (/books/(\\d+)) 可进行任意复杂的正则表达式匹配。请注意,括号不是正则表达式的一部分,而是将其内容定义为正则表达式。某些 API 禁止在URLPattern对象中使用正则表达式组。hasRegExpGroups属性指示是否使用了正则表达式组。
您可以在下面的模式语法部分找到有关语法的详细信息。
接口
URLPattern-
表示可以匹配 URL 或 URL 部分的模式。该模式可以包含捕获组,用于提取匹配 URL 的部分。
模式语法
模式的语法基于 path-to-regexp JavaScript 库。此语法类似于 Ruby on Rails 或 Express 或 Next.js 等 JavaScript 框架中使用的语法。
固定文本和捕获组
每个模式都可以包含固定文本和组的组合。固定文本是精确匹配的字符序列。组根据匹配规则匹配任意字符串。每个 URL 部分都有其自己的默认规则,如下所述,但它们可以被覆盖。
// A pattern matching some fixed text
const pattern = new URLPattern({ pathname: "/books" });
console.log(pattern.test("https://example.com/books")); // true
console.log(pattern.exec("https://example.com/books").pathname.groups); // {}
// A pattern matching with a named group
const pattern = new URLPattern({ pathname: "/books/:id" });
console.log(pattern.test("https://example.com/books/123")); // true
console.log(pattern.exec("https://example.com/books/123").pathname.groups); // { id: '123' }
段通配符
默认情况下,匹配 URL 的 pathname 部分的组将匹配除正斜杠 (/) 之外的所有字符。在 hostname 部分中,该组将匹配除点 (.) 之外的所有字符。在所有其他部分中,该组将匹配所有字符。段通配符是非贪婪的,这意味着它将匹配最短的可能字符串。
正则表达式匹配器
您可以为每个组指定一个正则表达式,而不是使用组的默认匹配规则,方法是在括号中指定它。此正则表达式定义了组的匹配规则。下面是一个命名组上的正则表达式匹配器的示例,它将组限制为仅当它包含一个或多个数字时才匹配。
const pattern1 = new URLPattern("/books/:id(\\d+)", "https://example.com");
console.log(pattern1.test("https://example.com/books/123")); // true
console.log(pattern1.test("https://example.com/books/abc")); // false
console.log(pattern1.test("https://example.com/books/")); // false
您还可以使用对象语法构造 URLPattern 时使用正则表达式。
const pattern2 = new URLPattern({ pathname: "/books/:id(\\d+)" });
console.log(pattern2.test("https://example.com/books/123")); // true
console.log(pattern2.test("https://example.com/books/abc")); // false
console.log(pattern2.test("https://example.com/books/")); // false
路径名匹配
pathname URL 部分始终以 / 开头。如果您在正则表达式中省略 /,则匹配将失败。下面的示例:
// Doesn't match, because omits the `/`
const pattern1 = new URLPattern({ pathname: "(b.*)" });
console.log(pattern1.test("https://example.com/b")); // false
console.log(pattern1.test("https://example.com/ba")); // false
以下示例包含 /
// Matches URL where path is exactly "/b"
const pattern2 = new URLPattern({ pathname: "(/b)" });
console.log(pattern2.test("https://example.com/b")); // true
console.log(pattern2.test("https://example.com/ba")); // false
// Matches URL where path is /b followed by any number of characters
const pattern3 = new URLPattern({ pathname: "(/b.*)" });
console.log(pattern3.test("https://example.com/b")); // true
console.log(pattern3.test("https://example.com/ba")); // true
行首和行尾锚点
行首锚点 (^) 和行尾锚点 ($) 用于将模式分别锚定到测试字符串的开头和结尾。虽然这些可以为 URL 部分的开头和结尾指定,但它们是冗余的。这是因为所有 URL 部分都隐式地以 ^ 锚点为前缀,并以 $ 锚点为后缀。
以下代码演示了是否指定 ^ 都没有关系。该示例在 protocol URL 部分中使用模式,但 URL 的其他部分行为相同。
// with `^` in protocol
const pattern1 = new URLPattern({ protocol: "(^https?)" });
console.log(pattern1.test("https://example.com/index.html")); // true
// without `^` in protocol
const pattern2 = new URLPattern({ protocol: "(https?)" });
console.log(pattern2.test("https://example.com/index.html")); // true
以下代码演示了是否指定 $ 都没有关系。
// with `$` in pathname
const pattern1 = new URLPattern({ pathname: "(/path$)" });
console.log(pattern1.test("https://example.com/path")); // true
// without `$` in pathname
const pattern2 = new URLPattern({ pathname: "(/path)" });
console.log(pattern2.test("https://example.com/path")); // true
// with `$` in hash
const pattern3 = new URLPattern({ hash: "(/hash$)" });
console.log(pattern3.test("https://example.com/#hash")); // true
// without `$` in hash
const pattern4 = new URLPattern({ hash: "(/hash)" });
console.log(pattern4.test("https://example.com/#hash")); // true
先行和后行断言
先行断言和后行断言允许您指定当前解析位置之前或之后的文本匹配特定模式,而无需捕获该匹配或消耗这些字符。
有四种类型的断言:
(?=...):正向先行断言指定后续字符必须匹配的模式。(?!...):负向先行断言指定后续字符不得匹配的模式。(?<=...):正向后行断言指定先行字符必须匹配的模式。(?<!...):负向后行断言指定先行字符不得匹配的模式。
在使用先行和后行断言与 URLPattern 时要小心,因为您可能会发现某些行为不直观。例如,您希望以下先行断言匹配 /ab 的 pathname,但事实并非如此。
const pattern = new URLPattern({ pathname: "(/a(?=b))" });
console.log(pattern.test("https://example.com/ab")); // false
URLPattern 引擎将测试字符串与 pathname 模式匹配,首先找到 /a 的匹配项,然后断言测试 URL 中的下一个字符是 b——但不会消耗它。引擎在未消耗的字符 b 处继续匹配测试 URL,但模式中没有剩余的内容可以与之匹配,这会导致匹配失败。
为了使匹配成功,模式必须消耗测试字符串中的所有字符。要消耗 b 字符,您可以在表达式的末尾添加 b,添加 . 以匹配任何字符,或添加 .* 以匹配先行断言之后的所有字符。
// positive-lookahead
const pattern1 = new URLPattern({ pathname: "(/a(?=b).*)" });
console.log(pattern1.test("https://example.com/ab")); // true
console.log(pattern1.test("https://example.com/ax")); // false
下一个示例显示了 /a 的负向先行匹配,它后面不跟 b。请注意,断言后面跟着 .* 以消耗断言匹配的字符。
// negative-lookahead - matches /a<not b><anything>
const pattern2 = new URLPattern({ pathname: "(/a(?!b).*)" });
console.log(pattern2.test("https://example.com/ab")); // false
console.log(pattern2.test("https://example.com/ax")); // true
以下示例显示了匹配 /ba 等路径名的正向后行匹配。该模式匹配 /,然后是 . 以消耗下一个字符,然后断言前一个字符是 b,然后是 a。
// positive-lookbehind
const pattern = new URLPattern({ pathname: "(/.(?<=b)a)" });
console.log(pattern.test("https://example.com/ba")); // true
console.log(pattern.test("https://example.com/xa")); // false
此示例显示了一个负向后行匹配,它匹配 /<not b>a 等路径名。该模式匹配 /,然后是 . 以消耗下一个字符 (x),然后断言前一个字符不是 b,然后是 a。
// negative-lookbehind
const pattern4 = new URLPattern({ pathname: "(/.*(?<!b)a)" });
console.log(pattern4.test("https://example.com/ba")); // false
console.log(pattern4.test("https://example.com/xa")); // true
其他正则表达式匹配器限制
某些其他正则表达式模式可能无法按您预期的方式工作:
-
在 URLPattern 中的范围表达式中,括号需要转义,尽管它们在 RegExp 中不需要。
jsnew URLPattern({ pathname: "([()])" }); // throws new URLPattern({ pathname: "([\\(\\)])" }); // ok new RegExp("[()]"); // ok new RegExp("[\\(\\)]"); // ok
无名组和命名组
组可以是命名组或无名组。命名组通过在组名前添加冒号 (:) 来指定。未以冒号和名称为前缀的正则表达式组是无名组。无名组根据它们在模式中的顺序在匹配结果中按数字索引。
// A named group
const pattern = new URLPattern("/books/:id(\\d+)", "https://example.com");
console.log(pattern.exec("https://example.com/books/123").pathname.groups); // { id: '123' }
// An unnamed group
const pattern = new URLPattern("/books/(\\d+)", "https://example.com");
console.log(pattern.exec("https://example.com/books/123").pathname.groups); // { '0': '123' }
组修饰符
组也可以有修饰符。这些在组名之后(如果存在正则表达式,则在正则表达式之后)指定。有三个修饰符:? 使组可选,+ 使组重复一次或多次,以及 * 使组重复零次或多次。
// An optional group
const pattern = new URLPattern("/books/:id?", "https://example.com");
console.log(pattern.test("https://example.com/books/123")); // true
console.log(pattern.test("https://example.com/books")); // true
console.log(pattern.test("https://example.com/books/")); // false
console.log(pattern.test("https://example.com/books/123/456")); // false
console.log(pattern.test("https://example.com/books/123/456/789")); // false
// A repeating group with a minimum of one
const pattern = new URLPattern("/books/:id+", "https://example.com");
console.log(pattern.test("https://example.com/books/123")); // true
console.log(pattern.test("https://example.com/books")); // false
console.log(pattern.test("https://example.com/books/")); // false
console.log(pattern.test("https://example.com/books/123/456")); // true
console.log(pattern.test("https://example.com/books/123/456/789")); // true
// A repeating group with a minimum of zero
const pattern = new URLPattern("/books/:id*", "https://example.com");
console.log(pattern.test("https://example.com/books/123")); // true
console.log(pattern.test("https://example.com/books")); // true
console.log(pattern.test("https://example.com/books/")); // false
console.log(pattern.test("https://example.com/books/123/456")); // true
console.log(pattern.test("https://example.com/books/123/456/789")); // true
组分隔符
模式还可以包含组分隔符。这些是括在大括号 ({}) 中的模式片段。这些组分隔符不像捕获组那样在匹配结果中被捕获,但仍然可以对它们应用修饰符,就像组一样。如果组分隔符未被修饰符修改,则它们被视为其中的项只是父模式的一部分。组分隔符不能包含其他组分隔符,但可以包含任何其他模式项(捕获组、正则表达式、通配符或固定文本)。
// A group delimiter with a ? (optional) modifier
const pattern = new URLPattern("/book{s}?", "https://example.com");
console.log(pattern.test("https://example.com/books")); // true
console.log(pattern.test("https://example.com/book")); // true
console.log(pattern.exec("https://example.com/books").pathname.groups); // {}
// A group delimiter without a modifier
const pattern = new URLPattern("/book{s}", "https://example.com");
console.log(pattern.pathname); // /books
console.log(pattern.test("https://example.com/books")); // true
console.log(pattern.test("https://example.com/book")); // false
// A group delimiter containing a capturing group
const pattern = new URLPattern({ pathname: "/blog/:id(\\d+){-:title}?" });
console.log(pattern.test("https://example.com/blog/123-my-blog")); // true
console.log(pattern.test("https://example.com/blog/123")); // true
console.log(pattern.test("https://example.com/blog/my-blog")); // false
路径名中的自动组前缀
在匹配 URL 的 pathname 部分的模式中,如果组定义前面有斜杠 (/),则组会自动添加斜杠 (/) 前缀。这对于带修饰符的组很有用,因为它允许重复组按预期工作。
如果您不希望自动添加前缀,可以通过将组括在组分隔符 ({}) 中来禁用它。组分隔符没有自动添加前缀的行为。
// A pattern with an optional group, preceded by a slash
const pattern = new URLPattern("/books/:id?", "https://example.com");
console.log(pattern.test("https://example.com/books/123")); // true
console.log(pattern.test("https://example.com/books")); // true
console.log(pattern.test("https://example.com/books/")); // false
// A pattern with a repeating group, preceded by a slash
const pattern = new URLPattern("/books/:id+", "https://example.com");
console.log(pattern.test("https://example.com/books/123")); // true
console.log(pattern.test("https://example.com/books/123/456")); // true
console.log(pattern.test("https://example.com/books/123/")); // false
console.log(pattern.test("https://example.com/books/123/456/")); // false
// Segment prefixing does not occur outside of pathname patterns
const pattern = new URLPattern({ hash: "/books/:id?" });
console.log(pattern.test("https://example.com#/books/123")); // true
console.log(pattern.test("https://example.com#/books")); // false
console.log(pattern.test("https://example.com#/books/")); // true
// Disabling segment prefixing for a group using a group delimiter
const pattern = new URLPattern({ pathname: "/books/{:id}?" });
console.log(pattern.test("https://example.com/books/123")); // true
console.log(pattern.test("https://example.com/books")); // false
console.log(pattern.test("https://example.com/books/")); // true
通配符标记
通配符标记 (*) 是一个无名捕获组的简写,它匹配所有字符零次或多次。您可以将其放置在模式中的任何位置。通配符是贪婪的,这意味着它将匹配最长的可能字符串。
// A wildcard at the end of a pattern
const pattern = new URLPattern("/books/*", "https://example.com");
console.log(pattern.test("https://example.com/books/123")); // true
console.log(pattern.test("https://example.com/books")); // false
console.log(pattern.test("https://example.com/books/")); // true
console.log(pattern.test("https://example.com/books/123/456")); // true
// A wildcard in the middle of a pattern
const pattern = new URLPattern("/*.png", "https://example.com");
console.log(pattern.test("https://example.com/image.png")); // true
console.log(pattern.test("https://example.com/image.png/123")); // false
console.log(pattern.test("https://example.com/folder/image.png")); // true
console.log(pattern.test("https://example.com/.png")); // true
路径名中的尾部斜杠默认不匹配
路径名中的尾部斜杠不会自动匹配。下面的示例演示了 URLPattern 匹配 /books 的路径名将匹配 https://example.com/books,但不匹配 https://example.com/books/(反之亦然)。
const patternSlash = new URLPattern({ pathname: "/books/" });
console.log(patternSlash.test("https://example.com/books")); // false
console.log(patternSlash.test("https://example.com/books/")); // true
const patternNoSlash = new URLPattern({ pathname: "/books" });
console.log(patternNoSlash.test("https://example.com/books")); // false
console.log(patternNoSlash.test("https://example.com/books/")); // true
如果您想同时匹配两者,则需要使用允许两者之一的匹配模式。最简单的方法是使用包含正斜杠的组分隔符,后跟可选修饰符。这将匹配带或不带终止正斜杠的模式。
const patternOptionalSlash = new URLPattern({ pathname: "/books{/}?" });
console.log(patternOptionalSlash.test("https://example.com/books")); // true
console.log(patternOptionalSlash.test("https://example.com/books/")); // true
模式规范化
解析模式时,它会自动规范化为规范形式。例如,Unicode 字符在路径名属性中进行百分比编码,主机名中使用 punycode 编码,默认端口号被省略,/foo/./bar/ 等路径被折叠为 /foo/bar 等。此外,还有一些模式表示形式解析为相同的底层含义,例如 foo 和 {foo}。这种情况被规范化为最简单的形式。例如,在这种情况下,{foo} 被规范化为 foo。
从基本 URL 继承
在 URLPattern 中定义的匹配模式以及在 URLPattern.test() 和 URLPattern.exec() 中使用的测试 URL 都允许输入指定可选的基本 URL(当将 URL 指定为字符串时,此基本 URL 是一个单独的参数;当将 URL 指定为对象时,它是一个单独的属性)。
如果定义了基本 URL,则 URL 部分可能从基本 URL 继承,并用于设置模式或测试 URL 的部分。URL 解析与您在解析使用基本 URL 指定的 URL 时所期望的非常相似。
username 和 password 永远不会从基本 URL 继承。
只有比输入中定义的最特定部分“更具体”的 URL 部分才会从基本 URL 继承。以下列表显示了特异性顺序:
protocol(最具体)、hostname、port、pathname、search、hashprotocol、hostname、port、username、password
这意味着,例如,如果在输入 URL 中指定了 protocol,则没有更具体的内容,因此不会从基本 URL 继承任何内容。但是,如果在输入中指定了 pathname 部分,则 protocol、hostname 和 port 可能会从基本 URL 继承,但 search 和 hash 不会。
请注意,未在字符串/输入对象中指定或未从基本 URL 继承的 URL 组件将默认为 URLPattern 的通配符值 ("*") 和测试 URL 的空字符串 ("")。
区分大小写
URL 模式 API 在匹配时默认将 URL 的许多部分视为区分大小写。相比之下,许多客户端 JavaScript 框架使用不区分大小写的 URL 匹配。URLPattern() 构造函数上提供了 ignoreCase 选项,如果需要,可以启用不区分大小写的匹配。
// Case-sensitive matching by default
const pattern = new URLPattern("https://example.com/2022/feb/*");
console.log(pattern.test("https://example.com/2022/feb/xc44rsz")); // true
console.log(pattern.test("https://example.com/2022/Feb/xc44rsz")); // false
在构造函数中将 ignoreCase 选项设置为 true 会将所有匹配操作切换为给定模式的不区分大小写匹配。
// Case-insensitive matching
const pattern = new URLPattern("https://example.com/2022/feb/*", {
ignoreCase: true,
});
console.log(pattern.test("https://example.com/2022/feb/xc44rsz")); // true
console.log(pattern.test("https://example.com/2022/Feb/xc44rsz")); // true
示例
过滤特定 URL 组件
以下示例显示了 URLPattern 如何过滤特定 URL 组件。当使用组件模式的结构化对象调用 URLPattern() 构造函数时,任何缺失的组件都默认为 * 通配符值。
// Construct a URLPattern that matches a specific domain and its subdomains.
// All other URL components default to the wildcard `*` pattern.
const pattern = new URLPattern({
hostname: "{*.}?example.com",
});
console.log(pattern.hostname); // '{*.}?example.com'
console.log(pattern.protocol); // '*'
console.log(pattern.port); // '*'
console.log(pattern.username); // '*'
console.log(pattern.password); // '*'
console.log(pattern.pathname); // '*'
console.log(pattern.search); // '*'
console.log(pattern.hash); // '*'
console.log(pattern.test("https://example.com/foo/bar")); // true
console.log(pattern.test({ hostname: "cdn.example.com" })); // true
console.log(pattern.test("custom-protocol://example.com/other/path?q=1")); // true
// Prints `false` because the hostname component does not match
console.log(pattern.test("https://cdn-example.com/foo/bar"));
从完整 URL 字符串构造 URLPattern
以下示例显示了如何从包含嵌入模式的完整 URL 字符串构造 URLPattern。例如,: 既可以是 URL 协议后缀,如 https:,也可以是命名模式组的开头,如 :foo。如果字符是 URL 语法的一部分还是模式语法的一部分之间没有歧义,它就会“正常工作”。
// Construct a URLPattern that matches URLs to CDN servers loading jpg images.
// URL components not explicitly specified result in the wild string ("*")
const pattern = new URLPattern("https://cdn-*.example.com/*.jpg");
console.log(pattern.protocol); // 'https'
console.log(pattern.hostname); // 'cdn-*.example.com'
console.log(pattern.pathname); // '/*.jpg'
console.log(pattern.username); // '*'
console.log(pattern.password); // '*'
console.log(pattern.search); // '*'
console.log(pattern.hash); // '*'
// `true`
console.log(
pattern.test("https://cdn-1234.example.com/product/assets/hero.jpg"),
);
// `true` because the search pattern defaults to wildcard
console.log(
pattern.test("https://cdn-1234.example.com/product/assets/hero.jpg?q=1"),
);
构造具有歧义 URL 字符串的 URLPattern
以下示例显示了从歧义字符串构造的 URLPattern 如何倾向于将字符视为模式语法的一部分。在这种情况下,: 字符可以是协议组件后缀,也可以是模式中命名组的前缀。构造函数选择将其视为模式的一部分,因此确定这是一个相对路径名模式。由于没有基本 URL,因此无法解析相对路径名,并抛出错误。
// Throws because this is interpreted as a single relative pathname pattern
// with a ":foo" named group and there is no base URL.
const pattern = new URLPattern("data:foo*");
转义字符以消除 URLPattern 构造函数字符串的歧义
以下示例显示了如何转义歧义构造函数字符串字符以将其视为 URL 分隔符而不是模式字符。这里 : 被转义为 \\:。
// Constructs a URLPattern treating the `:` as the protocol suffix.
const pattern = new URLPattern("data\\:foo*");
console.log(pattern.protocol); // 'data'
console.log(pattern.pathname); // 'foo*'
console.log(pattern.username); // '*'
console.log(pattern.password); // '*'
console.log(pattern.hostname); // ''
console.log(pattern.port); // ''
console.log(pattern.search); // '*'
console.log(pattern.hash); // '*'
console.log(pattern.test("data:foobar")); // true
将基本 URL 用于 test() 和 exec()
以下示例显示了 test() 和 exec() 如何使用基本 URL。
const pattern = new URLPattern({ hostname: "example.com", pathname: "/foo/*" });
console.log(pattern.protocol); // '*'
console.log(pattern.pathname); // '/foo/*'
console.log(pattern.username); // '*'
console.log(pattern.password); // '*'
console.log(pattern.hostname); // 'example.com'
console.log(pattern.port); // '*'
console.log(pattern.search); // '*'
console.log(pattern.hash); // '*'
// `true` as the hostname is inherited from `baseURL` property
// (so is the protocol, but that is matched by the pattern wildcard)
console.log(
pattern.test({
pathname: "/foo/bar",
baseURL: "https://example.com/baz",
}),
);
// Prints `true` as the hostname in the second argument base URL matches.
console.log(pattern.test("/foo/bar", "https://example.com/baz"));
// Throws because the second argument cannot be passed with the object input.
try {
pattern.test({ pathname: "/foo/bar" }, "https://example.com/baz");
} catch (e) {}
// The `exec()` method takes the same arguments as `test()`.
const result = pattern.exec("/foo/bar", "https://example.com/baz");
console.log(result.pathname.input); // '/foo/bar'
console.log(result.pathname.groups[0]); // 'bar'
console.log(result.hostname.input); // 'example.com'
在 URLPattern 构造函数中使用基本 URL
以下示例显示了基本 URL 也可以用于构造 URLPattern。基本 URL 被严格视为 URL,不能包含任何模式语法本身。
该模式仅从基本 URL 继承比其他属性中更不具体的 URL 部分。
在这种情况下,指定了 pathname,因此可以继承协议和主机,但不能继承搜索、哈希、用户名或密码。未继承的属性默认为通配符字符串 ("*")。例外是端口,它被设置为空字符串,因为主机名是从基本 URL 继承的(它具有隐含的“默认端口”值)。
const pattern1 = new URLPattern({
pathname: "/foo/*",
baseURL: "https://example.com",
});
console.log(pattern1.protocol); // 'https'
console.log(pattern1.hostname); // 'example.com'
console.log(pattern1.pathname); // '/foo/*'
console.log(pattern1.username); // '*'
console.log(pattern1.password); // '*'
console.log(pattern1.port); // ''
console.log(pattern1.search); // '*'
console.log(pattern1.hash); // '*'
// Equivalent to pattern1
const pattern2 = new URLPattern("/foo/*", "https://example.com");
// Throws because a relative constructor string must have a base URL to resolve
// against.
try {
const pattern3 = new URLPattern("/foo/*");
} catch (e) {}
访问匹配组值
以下示例显示了如何从 exec() 结果对象访问匹配模式组的输入值。
input 属性是与模式匹配的字符串:在这种情况下是 cdn.example.com。groups 属性包含捕获的组,无名组按数字索引,命名组按名称索引。在这种情况下,通配符属性只有一个无名组,值为 cdn。
const pattern = new URLPattern({ hostname: "*.example.com" });
const result = pattern.exec({ hostname: "cdn.example.com" });
console.log(result.hostname); // {"groups": {"0": "cdn"}, "input": "cdn.example.com"}
访问匹配的命名组值
以下示例显示了如何为组指定自定义名称,这些名称可用于在结果对象中访问匹配值。
模式中的匹配模式由 : 符号后跟名称表示。相同的名称然后作为键出现在 groups 属性中,匹配值是测试 URL 的匹配部分。input 属性包含匹配 pathname 模式的 URL 的整个部分。
// Construct a URLPattern using matching groups with custom names.
const pattern = new URLPattern({ pathname: "/:product/:user/:action" });
const result = pattern.exec({ pathname: "/store/wanderview/view" });
console.log(result.pathname);
/*
{
"groups": {
"product": "store",
"user": "wanderview",
"action": "view"
},
"input": "/store/wanderview/view"
}
*/
// These names can then be later used to access the matched values
// in the result object, such as "user" below.
console.log(result.pathname.groups.user); // 'wanderview'
带无名组的正则表达式
以下示例显示了匹配组如何使用正则表达式匹配测试 URL 中的 /foo 或 /bar。该组是无名组,因此将通过结果中的索引号进行引用。
const pattern = new URLPattern({ pathname: "/(foo|bar)" });
console.log(pattern.test({ pathname: "/foo" })); // true
console.log(pattern.test({ pathname: "/bar" })); // true
console.log(pattern.test({ pathname: "/baz" })); // false
const result = pattern.exec({ pathname: "/foo" });
console.log(result.pathname.groups[0]); // 'foo'
带命名组的正则表达式
以下示例显示了如何使用带命名组的自定义正则表达式。
该组名为 type,匹配 /foo 或 /bar 的路径。
const pattern = new URLPattern({ pathname: "/:type(foo|bar)" });
const result = pattern.exec({ pathname: "/foo" });
console.log(result.pathname.groups.type); // 'foo'
使匹配组可选
以下示例显示了如何通过在其后放置 ? 修饰符使匹配组可选。
对于路径名组件,这也导致任何前面的 / 字符被视为组的可选前缀。
const pattern = new URLPattern({ pathname: "/product/(index.html)?" });
console.log(pattern.test({ pathname: "/product/index.html" })); // true
console.log(pattern.test({ pathname: "/product" })); // true
const pattern2 = new URLPattern({ pathname: "/product/:action?" });
console.log(pattern2.test({ pathname: "/product/view" })); // true
console.log(pattern2.test({ pathname: "/product" })); // true
通配符也可以是可选的。这可能看起来没有意义,因为它们已经匹配空字符串,但它也使路径名模式中的前缀 / 可选。
const pattern3 = new URLPattern({ pathname: "/product/*?" });
console.log(pattern3.test({ pathname: "/product/wanderview/view" })); // true
console.log(pattern3.test({ pathname: "/product" })); // true
console.log(pattern3.test({ pathname: "/product/" })); // true
使匹配组重复
以下示例显示了如何通过在其后放置 + 修饰符使匹配组重复。在 pathname 组件中,这也将 / 前缀视为特殊,因此它有效地成为重复组的开头。
const pattern = new URLPattern({ pathname: "/product/:action+" });
const result = pattern.exec({ pathname: "/product/do/some/thing/cool" });
console.log(result.pathname);
// { "groups": { "action": "do/some/thing/cool" }, "input": "/product/do/some/thing/cool" }
请注意,/product 不匹配,因为它后面没有 / 和至少一个字符。
console.log(pattern.test({ pathname: "/product" })); // false
console.log(pattern.test({ pathname: "/product/" })); // false
console.log(pattern.test({ pathname: "/product/do" })); // true
console.log(pattern.test({ pathname: "/product/do/" })); // false
使匹配组可选并重复
以下示例显示了如何创建既可选又重复的匹配组。通过在组后放置 * 修饰符来执行此操作。同样,路径名组件将 / 前缀视为特殊。
它既变为可选,又随组重复。
const pattern = new URLPattern({ pathname: "/product/:action*" });
const result = pattern.exec({ pathname: "/product/do/some/thing/cool" });
console.log(result.pathname);
// { "groups": { "action": "do/some/thing/cool" }, "input": "/product/do/some/thing/cool" }
请注意,与前面的示例不同,/product 匹配,因为重复的段(包括 /)是可选的。但是,在正斜杠后必须至少有一个字符才能捕获以匹配重复组。
console.log(pattern.test({ pathname: "/product" })); // true
console.log(pattern.test({ pathname: "/product/" })); // false
console.log(pattern.test({ pathname: "/product/do" })); // true
console.log(pattern.test({ pathname: "/product/do/" })); // false
为可选或重复修饰符使用自定义前缀或后缀
以下示例显示了如何将大括号(组分隔符)与命名组一起使用,以表示要由后续 ?、* 或 + 修饰符操作的自定义前缀和/或后缀。
例如,{:subdomain.}* 匹配 example.com 的任何子域和域本身。匹配被分配给命名组“subdomain”。
const pattern = new URLPattern({ hostname: "{:subdomain.}*example.com" });
const result = pattern.exec({ hostname: "foo.bar.example.com" });
console.log(pattern.test({ hostname: "example.com" })); // true
console.log(pattern.test({ hostname: "foo.bar.example.com" })); // true
console.log(pattern.test({ hostname: ".example.com" })); // false
console.log(result.hostname);
// { "groups": { "subdomain": "foo.bar" }, "input": "foo.bar.example.com" }
使文本可选或重复而无需匹配组
以下示例显示了如何使用大括号将固定文本值表示为可选或重复,而无需使用匹配组。
以下模式匹配 /product 或 /products/,但由于组分隔符默认不捕获,因此在相应的匹配组中找不到结果。
const pattern = new URLPattern({ pathname: "/product{/}?" });
console.log(pattern.test({ pathname: "/product" })); // true
console.log(pattern.test({ pathname: "/product/" })); // true
const result = pattern.exec({ pathname: "/product/" });
console.log(result.pathname.groups); // {}
同时使用多个组件和功能
以下示例显示了如何跨多个 URL 组件组合许多功能。
const pattern = new URLPattern({
protocol: "http{s}?",
username: ":user?",
password: ":pass?",
hostname: "{:subdomain.}*example.com",
pathname: "/product/:action*",
});
const result = pattern.exec(
"http://foo:bar@sub.example.com/product/view?q=12345",
);
console.log(result.username.groups.user); // 'foo'
console.log(result.password.groups.pass); // 'bar'
console.log(result.hostname.groups.subdomain); // 'sub'
console.log(result.pathname.groups.action); // 'view'
规范
| 规范 |
|---|
| URL 模式 |
浏览器兼容性
加载中…
另见
- 在 GitHub 上提供了
URLPattern的 polyfill - URLPattern 使用的模式语法与 path-to-regexp 使用的语法相似