如何将URL中的双斜杠替换为单斜杠

21

1
你尝试了什么?你知道谷歌吗? - Mickäel A.
您不需要使用正则表达式。可以使用String类上的简单方法来搜索//,在该点拆分字符串,并重新组装一个新值,而无需其中一个/字符。只有在搜索更复杂的模式时才需要使用正则表达式...并且它们不会改变拆分和重新组装任务的部分。 - keshlam
除了第一个之外,所有的双斜杠都需要替换。 - user3181223
1
你是如何首先获取这个URL的?在我看来,它很可能是由某些东西生成的...如果是这样,更好的方法可能是调整你的生成器,以避免产生双斜杠。 - user3334690
5个回答

31
为避免替换http://中的第一个 //,使用以下正则表达式:
String to = from.replaceAll("(?<!http:)//", "/");

PS:如果您想处理HTTPS,请使用(?<!(http:|https:))//


7
替换任意数量的斜杠:.replaceAll("(?<!(http:|https:))/+", "/"); - bhelm

21

正则表达式是正确的方法吗?

如果您希望将此解决方案作为提高正则表达式技能的练习的一部分,那很好。但您真正想要实现什么?您可能正在尝试规范化URL。用//替换/是规范化URL的一个方面。但其他方面呢?例如删除多余的./并将../与其父目录合并在一起?不同的协议呢?///怎么办?以及开头的//呢?文件协议的情况下,file:///开头的///呢?

如果您想编写通用的可重用代码,则使用正则表达式可能不是最佳方法。这是重新发明轮子。相反,请考虑使用java.net.URI.normalize()

java.net.URI.normalize()

java.lang.String

String inputUrl = "http://localhost:1234//foo//bar//buzz";
String normalizedUrl = new URI(inputUrl).normalize().toString();

java.net.URL

URL inputUrl = new URL("http://localhost:1234//foo//bar//buzz");
URL normalizedUrl = inputUrl.toURI().normalize().toURL();

java.net.URI

URI inputUri = new URI("http://localhost:1234//foo//bar//buzz");
URI normalizedUri = inputUri.normalize();

正则表达式

如果你确实需要使用正则表达式,请考虑所有可能性。如果将来这也应该处理其他协议,如httpsfileftpfish等等,那么怎么办呢?所以,请再次考虑,并可能使用URI.normalize()。但是,如果你坚持要使用正则表达式,也许可以使用这个:

String noramlizedUri = uri.replaceAll("(?<!\\w+:/?)//+", "/");
与其他解决方案相比,此解决方案适用于所有类似于HTTP URL但使用不同协议的URL,如httpsfileftp等,并且在file:///的情况下保留三个斜杠///。但是,与java.net.URI.normalize()不同的是,它不会删除冗余的./,也不会将../与其父目录合并,也不会处理URL标准化的其他方面,而我们可能已经忘记了,它也不会自动更新新的有关URL、URI和类似事项的RFC。

3
请注意,java.net.URI 构造函数会抛出一个已检查的异常。对于那些您知道是有效的字符串,请改用方便的静态工厂方法 java.net.URI.create - haisi

4
String to = from.replaceAll("(?<!(http:|https:))[//]+", "/");

将匹配两个或更多的斜杠。


1
Doesn't [//]+ only match even numbers of slashes? - fall
正如@fall所说,它只替换偶数个斜杠。foo////bar将变成foo/bar,但foo///bar将变成foo//bar - Christian Hujer

4

这里是正则表达式:

/(?<=[^:\s])(\/+\/)/g

它能够找到URL中的多个斜杠,无论协议如何,在协议后面保留斜杠。
同时处理以 // 开头的协议相对URL。

@Test
public void shouldReplaceMultipleSlashes() {
    assertEquals("http://google.com/?q=hi", replaceMultipleSlashes("http://google.com///?q=hi"));
    assertEquals("https://google.com/?q=hi", replaceMultipleSlashes("https:////google.com//?q=hi"));
    assertEquals("//somecdn.com/foo/", replaceMultipleSlashes("//somecdn.com/foo///"));
}

private static String replaceMultipleSlashes(String url) {
      return url.replaceAll("(?<=[^:\\s])(\\/+\\/)", "/");
}

字面意思是:
  • (\/+\/) - 查找组:/+ 一个或多个斜杠后跟 / 斜杠
  • (?<=[^:\s]) - 跟随该组的位置 (*积极回顾) 的这个 (*否定集合) [^:\s],不包括冒号 : 和空格 \s
  • g - 全局搜索标志

请注意,这只是IT技术相关内容的翻译,可能需要更多上下文才能完全理解。

1
前斜杠的转义是不是多余的?例如:(?<=[^:\s])(/+/) - Fraser

1
我建议您直接使用String.replace,它的文档是http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#replace(java.lang.CharSequence, java.lang.CharSequence)。
例如: `myString.replace("//", "/");
如果您想删除第一个出现的: String[] parts = str.split("//", 2); str = parts[0] + "//" + parts[1].replaceAll("//", "/");
这是最简单的方法(不使用正则表达式)。如果有专家正在查看该线程,则不知道相应的正则表达式... ;)

这将替换所有双斜杠为单斜杠。但我的要求是除了第一次出现外,它应该替换所有双斜杠。 - user3181223
在split中包含“:”而不是指定2是否更好?我认为当应用于提问者的示例时,str.split("//",2)会返回数组["http:", "google.com/"],但我可能错了... - user3334690
'split' 允许我们仅将字符串分成两部分,这可以防止在 parts[] 上之后使用 'for' 循环。http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#split(java.lang.String, int) - poitevinpm

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