【问题标题】:Regex to match text from multiple links正则表达式匹配来自多个链接的文本
【发布时间】:2019-08-19 13:53:23
【问题描述】:

如何提取包含某个单词的链接?

例如:

@987654321@<strong>word</strong>/2@@@@987654322@<strong>word</strong>/3@@@@987654323@<strong>word</strong>/3/text/text

如何从下面的正则表达式中搜索“word”?

((https:).*?(@@@))

结果应该是这样的

https://www.test.com/text//2

https://www.test.com/text/text//3

https://www.test.com/word/3/text/text

【问题讨论】:

  • 您可以在@@@ 上拆分并将数组项与/word/ 匹配
  • s.split('@@@').filter(x =&gt; x.indexOf('/word/') &gt; 0)

标签: regex


【解决方案1】:

让我们尝试构建这样的正则表达式。首先我们需要找到url的开头:

/(https?:\/\//

我们在https 之后为http 网址添加?

那么我们需要找到除@@@之外的任何文本,所以我们需要添加:

(?:(?!@@@).)*

这意味着 - 不以@@@ 序列开头的任意数量的字符。

我们还需要再次添加单词本身和之前的子表达式,因为单词可以被任何文本包围:

word(?:(?!@@@).)*

但问题是最后一个子表达式会跳过@@@之前的最后一个字符,所以我们需要再添加一个东西来处理它:

.(?=@@@|$)

这意味着 - 任何字符后跟@@@ 或字符串结尾。最终表达式将如下所示:

/(https:\/\/(?:(?!@@@).)*word(?:(?!@@@).)*.(?=@@@|$))/g

但我相信,最好只用@@@ 分割文本,然后用String.prototype.includes 检查需要的单词。

【讨论】:

  • 嗨@Andres,你的回答真的很有帮助,我们可以捕捉第一场比赛,第二场比赛等吗? '(https:\/\/(.(?!@@@))*word(.(?!@@@))*.(?=(@@@)|$)){first/second/third }'
  • 我修复了使用缓和贪婪令牌的常见问题,但/(https:\/\/(?:(?!@@@).)*word(?:(?!@@@).)*.(?=@@@|$))/g 看起来很可疑,因为.(?=@@@|$) 之前。
  • @WiktorStribiżew 我们可以通过将参数传递给正则表达式来捕获第二/第三/第四场比赛吗?
  • @MusakkhirSayyed 不,不是正则表达式,但您可以使用 Oracle SQL regexp_substr 和其他正则表达式驱动的类似函数轻松完成此操作。您只需使用代码即可。
【解决方案2】:

如果word 必须是路径名的一部分,您可以将filterURL 结合使用,并检查路径名的部分是否包含单词。

let str = 'https://www.test.com/text/1@@@https://www.test.com/text/word/2@@@https://www.test.com/text/text/word/3@@@https://www.test.com/3/text@@@https://www.test.com/word/3/text/text';
let filteredUrls = str.split("@@@")
  .filter(s =>
    new URL(s).pathname
    .split('/')
    .includes('word')
  );
console.log(filteredUrls);

如果您只想使用正则表达式并且支持possessive quantifiers(javascript 标签已被移除),您可以使用:

https?://[^@w]*(?:@(?!@@)|w(?!ord)|[^@w]*)++word.*?(?=@@@|$)

Regex demo

【讨论】:

  • 我们只能通过正则表达式来解决它吗?
  • @MusakkhirSayyed 我已经更新了答案并添加了一个可能的正则表达式解决方案。
【解决方案3】:

上一个答案

你肯定在寻找这个正则表达式:

https://www.test.com/(text/)*word/\d+(/text)*

这是在 JavaScript 上下文中使用它的方法(非常斜线 / 被反斜线 \/ 转义):

var str = 'https://www.test.com/text/1@@@https://www.test.com/text/word/2@@@https://www.test.com/text/text/word/3@@@https://www.test.com/3/text@@@https://www.test.com/word/3/text/text'; 
var urls = str.match(/https:\/\/www.test.com\/(text\/)*word\/\d+(\/text)*/g);
console.log(urls);

在数组中你得到你想要的元素。

更新问题并添加作者评论后更新答案

如果您需要从示例字符串中获取words,那么您必须使用更复杂的常规异常:

var str = 'https://www.test.com/text/1@@@https://www.test.com/text/word/2@@@https://www.test.com/text/text/word/3@@@https://www.test.com/3/text@@@https://www.test.com/word/3/text/text'; 
var urls = str.match(/(?<=\/)\w+(?=\/\d+\/\w)|(?<=(\w\/\w+\/))\w+(?=\/\d)/g);
console.log(urls);

说明

这是正则表达式/(?&lt;=(\w\/\w+\/))\w+(?=\/\d)|(?&lt;=\/)\w+(?=\/\d+\/\w)/g,受/.../ 限制,并带有g 标志强制模式搜索出现。

正则表达式有两种选择...|...

第一个 (?&lt;=\/)\w+(?=\/\d+\/\w) 捕获搜索词直接位于斜杠 (?&lt;=\/) 后面并且在数字 (?=\/\d+\/\w) 后面的更多词之前的情况。

https://www.test.com/word/3/text/text

第二种选择(?&lt;=(\w\/\w+\/))\w+(?=\/\d) 捕获的情况是,该词前面是域(?&lt;=(\w\/\w+\/)) 之后的其他词(实际上是由字母数字字符分隔的两个斜线),并且搜索的词紧跟在斜线之前,后跟数字@987654347 @。

https://www.test.com/text/word/2

https://www.test.com/text/text/word/3

所有斜线必须转义:\/

(?&lt;=...) 在正则表达式中表示 lookbehind(?=...) 在正则表达式中表示 lookahead

注意 1. 上面的例子目前只在 Chrome 浏览器中运行良好,如that:

(...) 现在lookbehind 是 ECMAScript 2018 规范的一部分。在撰写本文时(2018 年末),谷歌的 Chrome 浏览器是唯一一个支持后视的流行 JavaScript 实现。所以如果跨浏览器的兼容性很重要,你就不能在 JavaScript 中使用lookbehind。

注 2.Lookbehnd,即使它被正确解释,在大多数正则表达式引擎中必须包含一个 固定长度 正则表达式,我不保留上面的例子,因为这个仍然有效并且适用于谷歌浏览器的JavaScript engineJGsoft engine.NET framework RegEx classes中使用的正则表达式引擎。

注 3。lookbehind 语法或其较差的 \K 替换被大量编程语言中使用的许多正则表达式引擎广泛支持。

更多关于我使用的正则表达式的解释你可以找到例如here

【讨论】:

  • @MusakkhirSayyed 如果您需要任何更具体的提示、解释或描述,请告诉我
  • 我想应用一种通用方法来仅使用正则表达式从单个链接中搜索单词。不特定于包含文本/数字/域的示例。
  • @MusakkhirSayyed 你的问题提出了其他建议......很遗憾。
  • 但是感谢您的评论@MusakkhirSayyed。我会根据您的确切需要更新我的答案。 BDW:如果我理解你的话,那么接受的答案不是你需要的。
【解决方案4】:

你可以先用@@@分割,然后检查每个元素中是否存在/word/

var s = 'https://www.test.com/text/1@@@https://www.test.com/text/word/2@@@https://www.test.com/text/text/word/3@@@https://www.test.com/3/text@@@https://www.test.com/word/3/text/text';

var result = [];

s.split(/@@@/).forEach(function(el) {
   if (el.includes('/word/'))
    result.push(el);
})

// or else by using filter
// result = s.split(/@@@/).filter(el => el.includes('/word/'))

console.log(result);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多