【问题标题】:Conditional replacement with regex使用正则表达式进行条件替换
【发布时间】:2009-06-10 14:14:17
【问题描述】:

当谈到正则表达式时,我是一个相对新手,但我开始掌握它的窍门。我开始在 java 中编写一个方法来“链接”一个字符串 - 也就是说,扫描它以查找任何 url 引用(即“http://...”)或 看起来 像 web 的字符串地址(“www.example.com...”)

例如,如果我有一个如下所示的字符串:

My favorite site is http://www.example.com.  What is yours?

通过方法运行它后,你会得到一个字符串,上面写着:

My favorite site is <a href="http://www.example.com">http://www.example.com</a>.  What is yours?

在网上搜索了一段时间后,我终于能够拼凑出不同的表达方式,帮助我做我正在寻找的事情(一些例子包括实际 url 中 url 末尾的尾随句点,一些编码网址已经在锚标签等)

这是我目前所拥有的:

public static String toLinkifiedString(String s, IAnchorBuilder anchorBuilder)
{
    if (IsNullOrEmpty(s))
    {
        return Empty;
    }

    String r = "(?<![=\"\"\\/>])(www\\.|(http|https|ftp|news|file)(s)?://)([\\w+?\\.\\w+])+([a-zA-Z0-9\\~\\!\\@\\#\\$\\%\\^\\&amp;\\*\\(\\)_\\-\\=\\+\\\\\\/\\?\\.\\:\\;\\'\\,]*)?([^.|'|# |!])";

    Pattern pattern = Pattern.compile(r, Pattern.DOTALL | Pattern.UNIX_LINES | Pattern.CASE_INSENSITIVE);
    Matcher matcher = pattern.matcher(s);
    if (anchorBuilder != null)
    {
        return matcher.replaceAll(anchorBuilder.createAnchorFromUrl("$0"));
    }
    return matcher.replaceAll("<a href=\"$0\">$0</a>"); // group 0 is the whole expression
}

public interface IAnchorBuilder
{
    public String createAnchorFromUrl(String url);
}

还有一个简单的 toLinkifiedString 版本,它只接受字符串 s - 它只是调用 toLinkifiedString(s, null)

就像我说的那样,这种模式可以捕获我需要捕获的所有内容,并且 replaceAll 对每种情况都非常有效,除非链接以 www 开头。如果匹配以“www”而不是协议开头,如“http”或“ftp”,我想有条件地在结果链接前添加“http://”。那就是:

MyClass.toLinkifiedString("go to www.example.org") 

应该返回

go to <a href="http://www.example.com">www.example.org</a>

匹配组如下:

  • $0 - 找到的实际网址:http://www.example.orgwww.example.net
  • $1 - 协议匹配(“http://”或“www”表示无协议的链接)

我想我想做的事,在伪代码中是这样的:

matcher.replaceAll("<a href="(if protocol = "www", insert "http://" + url - otherwise, insert url">url</a>"

这可能吗?或者我是否应该对只能从以“http://...”开头的链接创建锚点感到满意 :)

感谢任何人提供的任何帮助

【问题讨论】:

  • 你不需要使用相当这么多的反斜杠。 :D
  • @mjd79:你的正则表达式很乱。即使您开始掌握它的窍门,您也不应该在没有完全理解它们的含义之前从 Internet 上复制示例。我可以在其中看到许多错误的假设(关于正确的字符转义和字符类的机制)。如何在文本中查找 URL 的问题已经多次出现,我建议您通过 Google 的方式查看 SO。至少这里的正则表达式通常带有经过验证的解释。 :)

标签: java regex replace


【解决方案1】:

对于您的具体问题,请务必使用 Tomalak 所说的回调函数。

对于所有这些斜线的问题,以及其他各种奇怪的东西......

这是您当前的跨行 Java 正则表达式:

(?<![=\"\"\\/>])
(www\\.|(http|https|ftp|news|file)(s)?://)
([\\w+?\\.\\w+])+
([a-zA-Z0-9\\~\\!\\@\\#\\$\\%\\^\\&amp;\\*\\(\\)_\\-\\=\\+\\\\\\/\\?\\.\\:\\;\\'\\,]*)?
([^.|'|# |!])

与非 Java 正则表达式相同(没有 Java 字符串转义):

(?<![=""\/>])
(www\.|(http|https|ftp|news|file)(s)?://)
([\w+?\.\w+])+
([a-zA-Z0-9\~\!\@\#\$\%\^\&amp;\*\(\)_\-\=\+\\\/\?\.\:\;\'\,]*)?
([^.|'|# |!])


这是对它有什么问题的描述...... :)

第一行 - 你在字符类中复制了",不需要转义/

第二行 - 好的,除了我不确定你对 (s)? 部分的要求是什么,因为无论如何你在前一组中有 https。

第三行 - 你知道你有一个字符类吗?量词不起作用。你可能想要(\w+?\.\w+)+。 (这是 Java 字符串中的 (\\w+?\\.\\w+)+。)

第四行 - 哇,这么多的逃跑!几乎都是不必要的。试试看:([a-zA-Z0-9~!@#$%^&amp;*()_\-=+\/?.:;',]*)?(再一次:([a-zA-Z0-9~!@#$%^&amp;*()_\\-=+\\/?.:;',]*)?

第五行 - 交替在字符类中没有任何作用。这样做:[^.'#!],如果你真的想阻止管道字符出现,请添加一个 |

将所有这些 cmets 放在一起提供了这个正则表达式:

(?<![="/>])
(www\.|(http|https|ftp|news|file)://)
(\w+?\.\w+)+
([a-zA-Z0-9~!@#$%^&*()_\-=+\/?.:;',]*)?
([^.'# !])

或者,再次为 Java 转义:

(?<![=\"/>])
(www\\.|(http|https|ftp|news|file)://)
(\\w+?\\.\\w+)+
([a-zA-Z0-9~!@#$%^&*()_\\-=+\\/?.:;',]*)?
([^.'# !])

注意这有多简单!

回到单行给出:

(?<![="/>])(www\.|(http|https|ftp|news|file)://)(\w+?\.\w+)+([a-zA-Z0-9~!@#$%^&*()_\-=+\/?.:;',]*)?([^.'# !])

(?<![=\"/>])(www\\.|(http|https|ftp|news|file)://)(\\w+?\\.\\w+)+([a-zA-Z0-9~!@#$%^&*()_\\-=+\\/?.:;',]*)?([^.'# !])

但我会坚持使用多行 - 一开始就敲(?x),它是一个忽略空格的有效正则表达式,你可以使用#s进行评论 - 只要正则表达式总是一件好事像这样!

【讨论】:

  • 虽然我可能会省略反斜杠和引号的转义,因为这是 Java 字符串要求,而不是正则表达式要求。大部分不确定性来自这样一个事实,即人们不断地混淆什么系统需要什么转义——有经验的人因为他们知道,没有经验的人因为他们不知道,讽刺的是。
  • 嗯,好点子。我已经添加了示例而没有逃避答案。希望我没有把两者都弄得太混乱……也许我应该完全删除 Java 的,而只需要一两行关于转义的快速行?
  • 感谢您抽出时间彻底解释 :) 转义的原因实际上比我更 Intellij - 当您粘贴字符串时它实际上会自动转义字符串,这是一种行为在某些情况下会变得非常烦人。
【解决方案2】:

看起来您需要一个回调函数来返回您可以使用的动态结果,而不是您当前在replaceAll() 中拥有的固定字符串。

我想你可以从这个问题的公认答案中得出一些结论:Java equivalent to PHP's preg_replace_callback

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2020-02-25
  • 1970-01-01
  • 2020-05-01
  • 2012-01-25
  • 1970-01-01
  • 2022-12-24
  • 2013-05-29
  • 2019-02-07
相关资源
最近更新 更多