14

初学者正则表达式问题。我在一个文本文件中有几行 JSON,每行都有稍微不同的字段,但是如果有的话,我想为每行提取 3 个字段,而忽略其他所有内容。我将如何使用正则表达式(在编辑板或其他任何地方)来做到这一点?

例子:

"url":"http://www.netcharles.com/orwell/essays.htm",
"domain":"netcharles.com",
"title":"Orwell Essays & Journalism Section - Charles' George Orwell Links",
"tags":["orwell","writing","literature","journalism","essays","politics","essay","reference","language","toread"],
"index":2931,
"time_created":1345419323,
"num_saves":24

我想提取 URL,TITLE,TAGS,

4

5 回答 5

27
/"(url|title|tags)":"((\\"|[^"])*)"/i

我想这就是你所要求的。我将立即提供一个解释。此正则表达式(由/ - 您可能不必将它们放在编辑板中分隔)匹配:

"

一个字面量"

(url|title|tags)

三个文字字符串“url”、“title”或“tags”中的任何一个 - 在正则表达式中,默认情况下,括号用于创建组,管道字符用于交替 - 就像逻辑“或”。要匹配这些文字字符,您必须转义它们。

":"

另一个文字字符串。

(

另一组的开始。(第 2 组)

    (

另一组 (3)

        \\"

文字字符串\"- 你必须转义反斜杠,否则它将被解释为转义下一个字符,你永远不知道会做什么。

        |

或者...

        [^"]

除双引号外的任何单个字符 方括号表示字符类/集,或要匹配的字符列表。任何给定的类都与字符串中的一个字符完全匹配。^在类的开头使用克拉 ( ) 会否定它,导致匹配器匹配类中不包含的任何内容。

    )

第三组结束...

    *

星号导致前面的正则表达式(在本例中为第 3 组)重复零次或多次,在本例中导致匹配器匹配任何可能在 JSON 字符串的双引号内的内容。

)"

第 2 组的结尾和文字".

我在这里做了一些不明显的事情,可能会派上用场:

  1. 第 2 组 - 当使用反向引用取消引用时- 将是分配给该字段的实际字符串。这在获取实际值时很有用。
  2. 表达式末尾的 i 使其不区分大小写。
  3. 组 1 包含捕获字段的名称。

编辑:所以我看到标签是一个数组。当我有机会考虑它时,我将在这里更新正则表达式。

您的新正则表达式是:

/"(url|title|tags)":("(\\"|[^"])*"|\[("(\\"|[^"])*"(,"(\\"|[^"])*")*)?\])/i

我在这里所做的只是将我一直使用的字符串正则表达式 ( "((\\"|[^"])*)") 替换为用于查找数组的正则表达式 ( \[("(\\"|[^"])*"(,"(\\"|[^"])*")*)?\])。没有那么容易阅读,是吗?好吧,用我们的 String Regex 代替 letter S,我们可以将其重写为:

\[(S(,S)*)?\]

它匹配一个文字左括号(因此是反斜杠),可选地后跟一个逗号分隔的字符串列表和一个右括号。我在这里介绍的唯一新概念是问号 ( ?),它本身就是一种重复。通常称为“使前面的表达式可选”,也可以认为是 0 或 1 匹配。

使用我们相同S的符号,这是整个肮脏的正则表达式:

/"(url|title|tags)":(S|\[(S(,S)*)?\])/i

如果它有助于看到它在行动中,这里是它的行动视图。

于 2013-01-16T01:43:11.600 回答
9

这个问题有点老了,但我在我的电脑上浏览了一下,发现了那个表达。我通过他作为 GIST,可能对其他人有用。

编辑:

# Expression was tested with PHP and Ruby
# This regular expression finds a key-value pair in JSON formatted strings
# Match 1: Key
# Match 2: Value
# https://regex101.com/r/zR2vU9/4
# http://rubular.com/r/KpF3suIL10

(?:\"|\')(?<key>[^"]*)(?:\"|\')(?=:)(?:\:\s*)(?:\"|\')?(?<value>true|false|[0-9a-zA-Z\+\-\,\.\$]*)

# test document
[
  {
    "_id": "56af331efbeca6240c61b2ca",
    "index": 120000,
    "guid": "bedb2018-c017-429E-b520-696ea3666692",
    "isActive": false,
    "balance": "$2,202,350",
    "object": {
        "name": "am",
        "lastname": "lang"
    }
  }
]
于 2016-02-01T11:50:20.557 回答
1

请尝试以下表达式:

/"(url|title|tags)":("([^""]+)"|\[[^[]+])/gm

解释:

第一捕获组 (url|title|tags):这是交替捕获字符 'url'、'title' 和 'tags' 字面意思(区分大小写)。

第二捕获组 ("([^""]+)"|[[^[]+]):

  • 第一种选择 "([^""]+)" 匹配 " 和 " 中的所有单词,包括 " 和 "
  • 2nd Alternative [[^[]+] 匹配 [ and ] 中的所有单词,包括 [ and ]

我在这里测试过

于 2021-07-12T15:19:12.300 回答
0

我调整了正则表达式以在我自己的库中使用 JSON。我在下面详细介绍了算法行为。

首先,对 JSON 对象进行字符串化。然后,您需要存储匹配子字符串的开始和长度。例如:

"matched".search("ch") // yields 3

对于 JSON 字符串,它的工作原理完全相同(除非您明确搜索逗号和大括号,在这种情况下,我建议您在执行正则表达式之前先对 JSON 对象进行一些转换(例如:、{、})。

接下来,您需要重构 JSON 对象。我编写的算法通过从匹配索引递归地向后检测 JSON 语法来做到这一点。例如,伪代码可能如下所示:

find the next key preceding the match index, call this theKey
then find the number of all occurrences of this key preceding theKey, call this theNumber
using the number of occurrences of all keys with same name as theKey up to position of theKey, traverse the object until keys named theKey has been discovered theNumber times
return this object called parentChain

有了这些信息,就可以使用正则表达式来过滤 JSON 对象以返回键、值和父对象链。

您可以在http://json.spiritway.co/看到我编写的库和代码

于 2015-04-17T23:06:16.067 回答
-1

为什么它必须是正则表达式对象?

在这里,我们可以先使用一个 Hash 对象,然后再去搜索它。

mh = {"url":"http://www.netcharles.com/orwell/essays.htm","domain":"netcharles.com","title":"Orwell Essays & Journalism Section - Charles' George Orwell Links","tags":["orwell","writing","literature","journalism","essays","politics","essay","reference","language","toread"],"index":2931,"time_created":1345419323,"num_saves":24}

其输出将是

=> {:url=>"http://www.netcharles.com/orwell/essays.htm", :domain=>"netcharles.com", :title=>"Orwell Essays & Journalism Section - Charles' George Orwell Links", :tags=>["orwell", "writing", "literature", "journalism", "essays", "politics", "essay", "reference", "language", "toread"], :index=>2931, :time_created=>1345419323, :num_saves=>24}

并不是说我想避免使用正则表达式,但是您不认为在获得要进一步搜索的数据之前一次更容易地采取一步吗?只是MHO。

mh.values_at(:url, :title, :tags)

输出:

["http://www.netcharles.com/orwell/essays.htm", "Orwell Essays & Journalism Section - Charles' George Orwell Links", ["orwell", "writing", "literature", "journalism", "essays", "politics", "essay", "reference", "language", "toread"]]

采用 FrankieTheKneeman 给您的模式:

pattern = /"(url|title|tags)":"((\\"|[^"])*)"/i

我们可以通过将 mh 哈希转换为 json 对象来搜索它。

/#{pattern}/.match(mh.to_json)

输出:

=> #<MatchData "\"url\":\"http://www.netcharles.com/orwell/essays.htm\"" 1:"url" 2:"http://www.netcharles.com/orwell/essays.htm" 3:"m">

当然,这一切都是在 Ruby 中完成的,这不是您拥有的标签,但我希望与之相关。

但是哎呀!看起来我们不能用这种模式一次完成所有三个,所以我一次只做一个。

pattern = /"(title)":"((\\"|[^"])*)"/i

/#{pattern}/.match(mh.to_json)

#<MatchData "\"title\":\"Orwell Essays & Journalism Section - Charles' George Orwell Links\"" 1:"title" 2:"Orwell Essays & Journalism Section - Charles' George Orwell Links" 3:"s">

pattern = /"(tags)":"((\\"|[^"])*)"/i

/#{pattern}/.match(mh.to_json)

=> nil

对不起最后一个。它必须以不同的方式处理。

于 2014-12-30T17:17:50.007 回答