正则表达式:如何从URL中删除主机名和端口?

14
我需要编写一些 JavaScript 代码来从 URL 中剥离主机名和端口号部分,也就是提取路径部分。
例如,我想编写一个函数 getPath(url),使得 getPath("http://host:8081/path/to/something") 返回 "/path/to/something"。
可以使用正则表达式来实现吗?

这根本不需要正则表达式 - 参见我的答案 :) - James
这并不是说它不需要正则表达式。这个应该不使用正则表达式来完成。 - Matthew Brubaker
但是了解这还是很有用的。 - arxpoetica
6个回答

29

RFC 3986(http://www.ietf.org/rfc/rfc3986.txt)在附录B中说明:

以下行是将格式良好的URI引用分解为其组成部分的正则表达式。

  ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
   12            3  4          5       6  7        8 9
第二行中的数字仅用于辅助阅读;它们表示每个子表达式的参考点(即,每对括号)。我们将子表达式匹配的值称为$。例如,将上述表达式与进行匹配。
  http://www.ics.uci.edu/pub/ietf/uri/#Related

导致以下子表达式匹配结果:

  $1 = http:
  $2 = http
  $3 = //www.ics.uci.edu
  $4 = www.ics.uci.edu
  $5 = /pub/ietf/uri/
  $6 = <undefined>
  $7 = <undefined>
  $8 = #Related
  $9 = Related

其中<undefined>表示该组件不存在,就像上面的示例中的查询组件一样。因此,我们可以确定五个组件的值为

  scheme    = $2
  authority = $4
  path      = $5
  query     = $7
  fragment  = $9

3
正则表达式错误地被 ** 和 ** 包围。 - Rene Saarsoo
1
非常详细的回复,我觉得很有用,虽然不像被采纳的答案那么直接。谢谢。 - lucasrizoli

14
我知道正则表达式很有用,但在这种情况下并不是必需的。Location对象是DOM中所有链接的固有属性,并具有pathname属性。
因此,要访问某个随机URL的该属性,您可能需要创建一个新的DOM元素,然后返回其pathname。
下面是一个永远完美运行的示例:
function getPath(url) {
    var a = document.createElement('a');
    a.href = url;
    return a.pathname.substr(0,1) === '/' ? a.pathname : '/' + a.pathname;
}

jQuery版本:(使用正则表达式添加前导斜杠(如果需要))

function getPath(url) {
    return $('<a/>').attr('href',url)[0].pathname.replace(/^[^\/]/,'/');
}

我知道这是一篇旧帖子,但我真的很喜欢你的方法J-P :) - Ben
1
请注意,这只适用于具有DOM的环境。在像Node.js或Web Workers这样的环境中,是没有DOM的。(可能在2009年写这篇答案时不是常见情况...) - Peter

13

快速而简单的方法:

^[^#]*?://.*?(/.*)$

主机名和端口之后的所有内容(包括初始的 /)都被捕获在第一组中。


在正则表达式字面量形式中(需要转义“/”):/^.?://.?(/.*)$/.exec("http://example.com/folder/file.ext")[1] 返回 "/folder/file.ext"。 - Ates Goral
2
这个正则表达式有问题,它在第一组中捕获了路径、查询和片段。 - Mike Samuel
正则表达式完全不是必须的!不过它还是很好用的! - James
@mikesamuel,问题要求删除主机名和端口号。我会更正我的答案并提供适当的解释。 - strager
@strager,这个方法是否仍会将一些没有方案或权限部分的URL转换为具有这些部分的URL。例如,#foo://bar//example.com/没有方案或权限,但您的正则表达式将其更改为具有权限的协议相对URL //example.com/ - Mike Samuel
@Mike Samuel,非常正确。正如我所说,这是一种快速而肮脏的方法,并不是一个强大的解决方案。您可以通过在协议中使用“[^#] *?”而不是“.*?”来解决此问题。我将更新我的答案以反映这一点。 - strager

4

窗口位置对象有pathname、search和hash属性,它们包含您需要的内容。

对于此页面

location.pathname = '/questions/441755/regular-expression-to-remove-hostname-and-port-from-url'  
location.search = '' //because there is no query string
location.hash = ''

因此,您可以使用

var fullpath = location.pathname+location.search+location.hash

2

1

这个正则表达式似乎有效:(http://[^/])(/.)

作为测试,我在文本编辑器中运行了这个搜索和替换:

 Search: (http://[^/]*)(/.*)
Replace: Part #1: \1\nPart #2: \2  

它将这段文本转换为:

http://host:8081/path/to/something

转换成这个:

Part #1: http://host:8081
Part #2: /path/to/something

并将其转换为:

https://dev59.com/nXRC5IYBdhLWcg3wAcM3

变成这样:

Part #1: http://stackoverflow.com
Part #2: /questions/441755/regular-expression-to-remove-hostname-and-port-from-url

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接