【问题标题】:how to use a regular expression to extract json fields?如何使用正则表达式提取 json 字段?
【发布时间】:2012-12-30 06:27:22
【问题描述】:

初学者正则表达式问题。我在文本文件中有几行 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,

【问题讨论】:

  • 我知道这可能不是您想要的,但您确实需要 JSON 解析器,而不是正则表达式。
  • 不要尝试自己解析 JSON。这是一个已解决的问题。人们已经编写、测试和调试了处理这个问题的代码。每当您遇到其他人可能不得不处理的编程问题时,请寻找可以为您解决的现有代码。
  • @AndyLester,这仍然是一个相关问题,因为有时您别无选择,只能使用正则表达式(例如在 2020 年处理 AWS CloudWatch 日志解析时)。
  • 如果您的 JSON 字符串无法解析! (这是一个不同的“Dave S”,但当我看到我们共享用户名时,我不得不加上我的 2 美分。)

标签: regex json text replace editpad


【解决方案1】:
/"(url|title|tags)":"((\\"|[^"])*)"/i

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

"

文字"

(url|title|tags)

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

":"

另一个文字字符串。

(

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

    (

另一组 (3)

        \\"

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

        |

或者...

        [^"]

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

    )

第 3 组结束...

    *

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

)"

第 2 组的结尾,以及文字 "

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

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

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

您的新正则表达式是:

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

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

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

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

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

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

如果看到它的实际效果有帮助,这里是a view of it in action.

【讨论】:

  • 嗨@FrankieTheKneeMan 如果您想提取索引值,这将如何改变,并且整个 json 以方括号和大括号开头,例如。 [{"index":2931,"num_saves":24
【解决方案2】:

这个问题有点老了,但我在我的电脑上浏览了一下,发现了那个表达。我通过了他作为 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"
    }
  }
]

【讨论】:

  • 观察:使用上述表达式,除非 JSON 格式不正确,否则当 value 的长度为 0 时,以下文本要么是对象的一部分,要么是数组的一部分。最终它带来了使用正则表达式和一点点编程来完全解析 JSON 的可能性!
【解决方案3】:

我在自己的库中调整了正则表达式以使用 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/看到我编写的库和代码

【讨论】:

    【解决方案4】:

    请尝试以下表达式:

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

    解释:

    1st Capturing Group (url|title|tags):这是交替地从字面上捕获字符“url”、“title”和“tags”(区分大小写)。

    第二个捕获组(“([^”“]+)”|[[^[]+]):

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

    我已经测试过here

    【讨论】:

      【解决方案5】:

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

      这里我们可以先使用一个 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
      

      对最后一个感到抱歉。必须以不同的方式处理。

      【讨论】:

      • 1.) 什么是 Hash 对象? 2.) 这如何回答如何用 RegEx 解决这个问题?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多