【问题标题】:How can I extract URLs from a huge one line text file?如何从一个巨大的单行文本文件中提取 URL?
【发布时间】:2019-04-12 13:32:58
【问题描述】:

我有一个要从中提取链接的文本文件。

问题是文本文件只有一行,链接很多!

或者当我在记事本中打开它时,它会显示在很多文件中但没有组织。

示例文本:

[{“参与者”:[“minanageh379”,“xcsadc”],“对话”: [{“发件人”:“minanageh379”,“created_at”: “2019-04-12T12:51:56.560361+00:00”,“媒体”: "https://scontent-lax3-1.cdninstagram.com/vp/edddf95178aca7bf75930ab8698ee45b/5D45203B/t51.2885-15/fr/e15/s1080x1080/55823673_114448266206459_7321604432125975069_n.jpg?_nc_ht=scontent-lax3-1.cdninstagram.com&ig_cache_key=Mjg2ODYwNDMxNzU3OTI1MTE1NTAxNjQ1NTk5MDkwOTMzNzY%3D.2"}, {“发件人”:“minanageh379”,“created_at”: “2019-04-12T12:51:51.923138+00:00”,“文本”:“sd”},{“发件人”: “minanageh379”,“created_at”:“2019-04-12T12:51:41.689524+00:00”, “文本”:“sdsa”},{“发件人”:“xcsadc”,“created_at”: "2019-04-12T12:50:57.283147+00:00", "text": "????‍❤️‍????‍????"}, {"sender": “xcsadc”、“created_at”:“2019-04-12T12:39:35.248517+00:00”、“文本”: “czx”},{“发件人”:“xcsadc”,“created_at”: “2019-04-12T12:39:34.352752+00:00”,“文本”:“dsad”},{“发件人”: “xcsadc”、“created_at”:“2019-04-12T12:39:30.889023+00:00”、“媒体”: "https://scontent-lax3-1.cdninstagram.com/vp/e985406d6eac06bb11c2d6052c1821a2/5D508106/t51.2885-15/e15/s640x640/56218099_577906226037731_8663356006073884002_n.jpg?_nc_ht=scontent-lax3-1.cdninstagram.com&ig_cache_key=Mjg2ODYwMjk0MjA1ODQxNzYzNjM1OTI1ODMwMjYzMTExNjg%3D.2"}, {“发件人”:“xcsadc”,“created_at”:“2019-04-12T12:38:54.823472+00:00”, "text": "hi hi hi"}]}]

预期结果

https://scontent-lax3-1.cdninstagram.com/vp/edddf95178aca7bf75930ab8698ee45b/5D45203B/t51.2885-15/fr/e15/s1080x1080/55823673_114448266206459_7321604432125975069_n.jpg?_nc_ht=scontent-lax3-1.cdninstagram.com&ig_cache_key=Mjg2ODYwNDMxNzU3OTI1MTE1NTAxNjQ1NTk5MDkwOTMzNzY%3D.2

https://scontent-lax3-1.cdninstagram.com/vp/e985406d6eac06bb11c2d6052c1821a2/5D508106/t51.2885-15/e15/s640x640/56218099_577906226037731_8663356006073884002_n.jpg?_nc_ht=scontent-lax3-1.cdninstagram.com&ig_cache_key=Mjg2ODYwMjk0MjA1ODQxNzYzNjM1OTI1ODMwMjYzMTExNjg%3D.2

更新的

{"sender": "ncccy", "created_at": "2019-01-28T17:09:29.216184+00:00", "media": "https://scontent-lax3-1.cdninstagram.com/vp/57c43d748xcasc1abf58c890c5a6df042/5D199AE8/t51.2885-15/e15/p480x480/49913269_2181952555454636_8892094125900591548_n.jpg?_nc_ht=scontent-lax3-1.cdninstagram.com&ig_cache_key=Mjg1NjgsdasdAwNjgxNTk1OTY0OTIwMTA1NTMzNDQ%3D.2"},

【问题讨论】:

标签: url text copy notepad++ line


【解决方案1】:

试试这个:

首先,我们将删除所有不构成有效 url 一部分的字符以及引号和空格。在某些情况下,这将删除似乎导致 trouble 在记事本++ 上使用 boost 正则表达式的表情符号。

我们的第一个替换将是:

搜索:[^a-zA-Z0-9_\-.~:\/?#\[\]@!$&'()*+,;=%"\s]

替换为:(leave empty)

全部替换

(notepad++ 的未来版本可能不需要之前的步骤)

清理完毕后,我们进行如下替换:

搜索:(?i)(?:(?:(?!https?:).(?!https?:))*?"sender"\s*+:\s*+"([^"]*)"|\G)(?:.(?!"sender"\s*+:\s*+))*?(https?:.*?(?=[^a-zA-Z0-9_\-.~:\/?#\[\]@!$&'()*+,;=%]|https?:))|.*

替换:(?{1}\n\n\1\t\2:(?{2}\t\2)

全部替换

即使“文本”属性内部包含多个 url,这也应该可以工作。网址将由制表符分隔。

所以在对这个数据应用前面的过程之后:

[{"participants": ["minanageh379", "xcsadc"], "conversation": [{"sender": "minanageh379", "created_at": "2019-04-12T12:51:56.560361+00:00", "media": "https://scontent-lax3-1.cdninstagram.com/vp/edddf95178aca7bf75930ab8698ee45b/5D45203B/t51.2885-15/fr/e15/s1080x1080/55823673_114448266206459_7321604432125975069_n.jpg?_nc_ht=scontent-lax3-1.cdninstagram.com&ig_cache_key=Mjg2ODYwNDMxNzU3OTI1MTE1NTAxNjQ1NTk5MDkwOTMzNzY%3D.2   http://foo.barhttps://bar.foo"}, {"sender": "minanageh379", "created_at": "2019-04-12T12:51:51.923138+00:00", "text": "sd"}, {"sender": "minanageh379", "created_at": "2019-04-12T12:51:41.689524+00:00", "text": "sdsa"}, {"sender": "xcsadc", "created_at": "2019-04-12T12:50:57.283147+00:00", "text": "?‍❤️‍?‍?"}, {"sender": "xcsadc", "created_at": "2019-04-12T12:39:35.248517+00:00", "text": "czx"}, {"sender": "xcsadc", "created_at": "2019-04-12T12:39:34.352752+00:00", "text": "dsad"}, {"sender": "xcsadc", "created_at": "2019-04-12T12:39:30.889023+00:00", "media": "https://scontent-lax3-1.cdninstagram.com/vp/e985406d6eac06bb11c2d6052c1821a2/5D508106/t51.2885-15/e15/s640x640/56218099_577906226037731_8663356006073884002_n.jpg?_nc_ht=scontent-lax3-1.cdninstagram.com&ig_cache_key=Mjg2ODYwMjk0MjA1ODQxNzYzNjM1OTI1ODMwMjYzMTExNjg%3D.2"}, {"sender": "xcsadc", "created_at": "2019-04-12T12:38:54.823472+00:00", "text": "hi hi hi"}, {"sender": "no_media_no_text", "created_at": "2019-04-12T12:38:54.823472+00:00"}, {"sender": "url_inside_text", "created_at": "2019-04-12T12:38:54.823472+00:00", "text": "Hi! {check} this url: \"http://foo.bar\" another url: https://new.url.com/ yet another one: https://google.com/"}, {"sender": "ncccy", "created_at": "2019-01-28T17:09:29.216184+00:00", "media": "https://scontent-lax3-1.cdninstagram.com/vp/57c43d748xcasc1abf58c890c5a6df042/5D199AE8/t51.2885-15/e15/p480x480/49913269_2181952555454636_8892094125900591548_n.jpg?_nc_ht=scontent-lax3-1.cdninstagram.com&ig_cache_key=Mjg1NjgsdasdAwNjgxNTk1OTY0OTIwMTA1NTMzNDQ%3D.2"}, {"sender": "ny", "created_at": "2017-10-22T20:49:50.042588+00:00", "media": "https://scontent-lax3-1.cdninstagram.com/vp/19d94ea45c2102a0f7c97838ef546b93/5D14B3C3/t51.2885-15/e15/22708873_149637425772501_5029503881546039296_n.jpg?_nc_ht=scontent-lax3-1.cdninstagram.com&ig_cache_key=Mjc4MzA3MDIyMTI3NDE3Njc3NTQxNTM1NTI2MjQyMjIyMDg%3D.2"}, {"sender": "xcsadc", "created_at": "2019-04-12T12:39:35.248517+00:00", "text": "czx"}]}]

我们得到:

minanageh379    https://scontent-lax3-1.cdninstagram.com/vp/edddf95178aca7bf75930ab8698ee45b/5D45203B/t51.2885-15/fr/e15/s1080x1080/55823673_114448266206459_7321604432125975069_n.jpg?_nc_ht=scontent-lax3-1.cdninstagram.com&ig_cache_key=Mjg2ODYwNDMxNzU3OTI1MTE1NTAxNjQ1NTk5MDkwOTMzNzY%3D.2    http://foo.bar  https://bar.foo

xcsadc  https://scontent-lax3-1.cdninstagram.com/vp/e985406d6eac06bb11c2d6052c1821a2/5D508106/t51.2885-15/e15/s640x640/56218099_577906226037731_8663356006073884002_n.jpg?_nc_ht=scontent-lax3-1.cdninstagram.com&ig_cache_key=Mjg2ODYwMjk0MjA1ODQxNzYzNjM1OTI1ODMwMjYzMTExNjg%3D.2

url_inside_text http://foo.bar  https://new.url.com/    https://google.com/

ncccy   https://scontent-lax3-1.cdninstagram.com/vp/57c43d748xcasc1abf58c890c5a6df042/5D199AE8/t51.2885-15/e15/p480x480/49913269_2181952555454636_8892094125900591548_n.jpg?_nc_ht=scontent-lax3-1.cdninstagram.com&ig_cache_key=Mjg1NjgsdasdAwNjgxNTk1OTY0OTIwMTA1NTMzNDQ%3D.2

ny  https://scontent-lax3-1.cdninstagram.com/vp/19d94ea45c2102a0f7c97838ef546b93/5D14B3C3/t51.2885-15/e15/22708873_149637425772501_5029503881546039296_n.jpg?_nc_ht=scontent-lax3-1.cdninstagram.com&ig_cache_key=Mjc4MzA3MDIyMTI3NDE3Njc3NTQxNTM1NTI2MjQyMjIyMDg%3D.2

如果在原始输入(相同或不同的属性)上重复的 url,您可能会得到重复的 url。

处理后,您可以使用此正则表达式删除重复项:

搜索:(?i)\t(https?:\S++)(?=[^\n]+\1)

替换为:(nothing)

全部替换

【讨论】:

  • 这只会给出一个 URL。
  • 我在我的 regex101.com 示例中看到了三个网址
  • 是的,在 regex101 上,但在 Notepad++ 中试试
  • 好的,我发现第二个网址有问题。
  • 已修复。这很有趣,我没想到\S 在试图找到那些表情符号时遇到了问题。使用. 而不是[\s\S] 可以达到我通常在notepad++ 中推荐[\s\S] 的效果,以避免指定dotmatchall 修饰符
【解决方案2】:
  • Ctrl+H
  • 查找内容:(?:^|\G).*?"media": "(https://[^"]+)(?:(?!https:).)*
  • 替换为:$1\n
  • 检查环绕
  • 检查正则表达式
  • 取消选中. matches newline
  • 全部替换

说明:

(?:^|\G)            # beginning of line OR restart from last match position
.*?                 # 0 or more any character but newline, not greedy
"media": "          # literally
(                   # start group 1
  https://[^"]+     # https:// fllowed by 1 or more not double quote, the url
)                   # end group 1
(?:(?!https:).)*    # Tempered greedy token, make sure we haven't "https" after

替换:

$1         # content of group 1, the URL

给定示例的结果:

https://scontent-lax3-1.cdninstagram.com/vp/edddf95178aca7bf75930ab8698ee45b/5D45203B/t51.2885-15/fr/e15/s1080x1080/55823673_114448266206459_7321604432125975069_n.jpg?_nc_ht=scontent-lax3-1.cdninstagram.com&ig_cache_key=Mjg2ODYwNDMxNzU3OTI1MTE1NTAxNjQ1NTk5MDkwOTMzNzY%3D.2
https://scontent-lax3-1.cdninstagram.com/vp/e985406d6eac06bb11c2d6052c1821a2/5D508106/t51.2885-15/e15/s640x640/56218099_577906226037731_8663356006073884002_n.jpg?_nc_ht=scontent-lax3-1.cdninstagram.com&ig_cache_key=Mjg2ODYwMjk0MjA1ODQxNzYzNjM1OTI1ODMwMjYzMTExNjg%3D.2

屏幕截图:

【讨论】:

  • 它可以工作,但是如果我们从表达式中删除 *?"media": 以确保我们复制所有链接,即使是那些不是媒体的链接,并且有可能让发件人链接前的名称?就像这个 minanageh379 scontent-lax3-1.cdninstagram.com/vp/…
  • @minanageh: 1) 您可以删除"media": ,但保留之前的.*?。 2) 我去看看,但它有点复杂。
  • @minanageh:试试看:查找:(?:^|\G).*?"sender": "([^"]+)".*?"(https://[^"]+)(?:(?!https:).)* 替换:$1\t$2\n
  • 是的,发件人表达有效。只有一个问题.. 我尝试使用在线站点提取 url 然后我比较了您的表达结果和在线站点结果i.ibb.co/gt9rdc4/image.png 在线站点有 175 行,而记事本有 144
【解决方案3】:

虽然其他答案完全符合您的需要,但需要注意的一点是您提供的字符串是有效的 JSON 字符串。您可以验证它是有效的 JSON here

如果您在程序中处理此字符串,您可能需要考虑为您的语言使用 JSON 解析器。 Here's the one for Python

【讨论】:

  • 非常有用的信息。但是,这可能属于评论而不是答案。
  • 您可以考虑添加自己的 json 解析...如果是这样,我不介意支持这个答案
【解决方案4】:

要仅从文本文件中提取链接,请使用以下内容执行正则表达式 Replace All:

找到什么:

.*?(https?:[^"]+)(?(?!.*?https?:).*)

替换为:

$1\n\n

Demo 1 ?

请注意,如果插入点不在文本开头,则需要选中 Wrap around

说明:

.*?(https?:[^"]+)(?(?!.*?https?:).*)
|_||____________||_________________|
 |    ____|               |
 |   |    ________________|
 |   |   |
 |   |  [3] If there are no more following links, grab and discard the rest of the text
 |  [2] Store the link in $1 (starting with http and ending just before the first following")
[1] Grab and discard everything up 'til the first link (i.e. starting with http: or https:)

当使用全部替换时,搜索和替换会自动继续,直到正则表达式匹配失败,从数据匹配的最后一点开始 'til,在这种情况下,它正好在末尾的双引号之前如果有更多链接,则为当前链接,否则为文本结尾。



要同时提取发件人,请使用以下命令:

找到什么:

.*?\{(?:([^"]*)"){4}[^{}]*?(https?:[^"]+)(?(?!.*?https?:).*)

替换为:

$1 $2\n\n

Demo 2 ?

说明:

明天来


一个替代的正则表达式做同样的事情,但可能更清楚一点是:

.*?"sender": "([^"]*)[^}]*?(https?:[^"]+)(?(?!.*?https?:).*)

Demo 3 ?

说明:

.*?"sender": "([^"]*)[^}]*?(https?:[^"]+)(?(?!.*?https?:).*)
|_||_________||_____||____||____________||_________________|
 |   ___|  ______|  ___|  _______|  _____________|
 |  |   __|  ______|  ___|  _______|
 |  |  |   _|   _____|  ___|
 |  |  |  |   _|  _____|
 |  |  |  |  |   |
 |  |  |  |  |  [6] If there are no more following links, grab and discard the rest of the text
 |  |  |  | [5] Store the link in $2 (starting with http and ending just before the first following")
 |  |  | [4] Grab and discard everything within the current set of braces up 'til the link
 |  | [3] Store the sender name in $1 
 | [2] Grab and discard "sender": " (i.e. up to the opening quote of the sender name)
[1] Grab and discard everything up 'til the first "sender" key which has an associated link

步骤 [1] 的工作原理是,最初从文本的开头开始抓取所有内容,直到第一个发件人密钥,然后通过 [2] 抓取密钥,抓取 [3] 中的发件人姓名,然后抓取所有内容直到关联的链接(如果它存在于 [4] 中)。如果没有关联的链接,[5] 失败,并且正则表达式回溯到步骤 [1],继续抓取从第一个发件人密钥到第二个发件人密钥之后的所有内容。重复此循环,直到找到具有关联链接的发送者密钥。

此时,步骤 [5] 成功,然后步骤 [6] 要么抓取其余文本,要么什么都不抓取。

最后,所有抓取的文本都被$1 $2\n\n替换,即发件人姓名后跟一个空格、链接和两个换行符。

这完成了第一个“替换”。由于选择了全部替换,整个过程再次开始,但文本指针位于先前找到的链接末尾的双引号中,或者位于文本末尾而不是开头。

【讨论】:

  • 您可能需要考虑我的新测试。我认为您的正则表达式可能会因字符串中的大括号和 url 而失败
  • .*?"sender": "([^"]*)[^}]*?(https?:[^"]+)(?(?!.*?https?: ).*) 这个只有 165 行,这个也是 .*?\{(?:([^"]*)"){4}[^{}]*?(https?:[^"] +)(?(?!.*?https?:).*) ......这与 175 行的输出完美配合。*?(https?:[^"]+)(? (?!.*?https?:).*)
【解决方案5】:

另一种选择是解析 JSON 数据。

您可以使用 javascript 来做到这一点。

以下代码片段应该可以用于解析您的数据。它甚至可以与同一 text 消息中的多个 url 一起使用:

yourJSON
[0].conversation
.filter(x => x.media !== undefined || x.text !== undefined && /https?:/i.test(x.text))
.map(x => {
    const tmp = x.text + ' ' + x.media;
    const urls = tmp.match(/https?:[\w\-.~:\/?#\[\]@!$&'()*+,;=%]*/g);
    return x.sender + ":\n" + urls.join("\n");
})
.join("\n\n");

您可以将该 javascript(使用您的数据更改 yourJSON)粘贴到具有 Firefox 或 Chrome 等 javascript 控制台的浏览器中。在Firefox中,您可以使用(Control + Shift + K)启动控制台,在Chrome中使用(Control + Shift + I,然后单击“控制台”)

作为替代方案,您可以改用 jsfiddle

编辑javascript 方块以使用您的数据,然后按“运行”按钮。

【讨论】:

  • 将数据粘贴到 jsfiddle 后浏览器刚刚挂起 .. :)
  • @minanageh 你能分享整个数据吗?也许你可以把它放到 pastebin.com
猜你喜欢
  • 1970-01-01
  • 2015-09-07
  • 2011-11-21
  • 1970-01-01
  • 1970-01-01
  • 2022-11-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多