Ruby解析字符串

3

我有一个字符串看起来像下面这样,我必须删除第一个括号和最后一个括号之间的所有内容。关于其他括号中的内容,一切都不确定。请问最好的方法是什么,谢谢。

'[

        { "foo":
            {"bar":"foo",
                "bar": {
                    ["foo":"bar", "foo":"bar"]
                }
            }
        }

    ],

"foo":"bar","foo":"bar"'

结果:

  ',

    "foo":"bar","foo":"bar"'

您的示例数据似乎不是有效的 JSON 格式。这是您预期的吗?存在以下偏差:最内层的数组使用了键值对,因此应该是一个对象。而最外层的作用域似乎是一个列表,但它包含 [] 和键值对 "":"",因此它既不是对象主体也不是数组主体。请问这是您想要的方式吗? - Nigel Thorne
5个回答

1
如果您的数据确实看起来像那样,并且在结尾处没有括号,则:
s.gsub(/\[.*\]/m, '')

如果你想更加谨慎一些,那么你可以寻找],后面跟着一个行尾符号。
s.gsub(/\[.*\],$/m, ',')

如果没有您数据格式的规范,很难再做更多解释。


好的,观察得很仔细,实际上结尾处的位可能有括号。我必须找到第一个开括号对应的闭括号,并删除两者之间的内容。顺便说一下,这是JSON格式,但我不能像处理哈希表那样处理它,因为顺序很重要,真是太麻烦了。所以,这个方法几乎可以解决问题,但如果末尾也有括号怎么办呢?谢谢! - dt1000
@dt1000:但是你在问题中发布的不是JSON。你可能需要使用真实数据(或至少有效的虚假数据)更新你的问题。我想你排除了修复JSON生成器以生成合理的JSON(即有序的事物在数组中)的可能性? - mu is too short
@dt1000:另外,你如何准确地确定要删除的部分? - mu is too short
不确定这是否可读,但我正在尝试删除键“thingToRemove”及其值,谢谢。'{ "groupRateSDI":"0.125","groupRate":"0.55", "coverageLevels":[".5",".6" ],"thingToRemove": [ { "memberCoverage": {"formula":"Formulas.levelsMultiplier", "parameters": { "type":"memberCoverage" } } }, { "memberMaxIncrements": {"formula":"Formulas.maxIncrement", "parameters": { "type":"member", "incrementType":"salaryMultiplierCoverageArray" } } } ],"someKey":"800","someKey2":"180"}' - dt1000
@dt1000:你知道在JSON中键应该按什么顺序吗?如果知道,你可以将其解析为JSON,剪切掉不需要的内容,然后逐个部分地放回JSON格式。 - mu is too short
不,我唯一知道的是json文件是一个哈希表,而且会有一个名为'thingToRemove'的键,其值比较复杂,需要被删除。我可以逐个字符地解析字符串并以此方式删除它,但由于我对Ruby还很陌生,所以在解析字符串的每个字符时遇到了麻烦。你有什么想法吗?谢谢。 - dt1000

0

你需要多行模式:

str.gsub(/\[.*\]/m, '')

0
你可以使用类似 Parslet 的工具来编写解析器。 这是我基于 http://www.json.org/ 的 JSON 语法所写的一个示例。
require 'parslet'

#This needs a few more 'as' calls to annotate the output 
class JSONParser < Parslet::Parser
  rule(:space)              { match('[\s\n]').repeat(1)}
  rule(:space?)             { space.maybe }
  rule(:digit)              { match('[0-9]') }
  rule(:hexdigit)           { match('[0-9a-fA-F]') }

  rule(:number)             { space? >> str('-').maybe >> 
                                (str('0') | (match('[1-9]') >> digit.repeat)) >> 
                                (str('.') >> digit.repeat).maybe >> 
                                ((str('e')| str('E')) >> (str('+')|str('-')).maybe >> digit.repeat ).maybe }

  rule(:escaped_character)  { str('\\') >> (match('["\\\\/bfnrt]') | (str('u') >> hexdigit.repeat(4,4))) }
  rule(:string)             { space? >> str('"') >> (match('[^\"\\\\]') | escaped_character).repeat >> str('"') }
  rule(:value)              { space? >> (string | number | object | array | str('true') | str('false') | str('null')) }

  rule(:pair)               { string >> str(":") >> value }
  rule(:pair_list)          { pair >> (space? >> str(',') >> pair).repeat }
  rule(:object)             { str('{') >> space? >> pair_list.maybe >> space? >> str('}') }

  rule(:value_list)         { value >> (space? >> str(',') >> value).repeat }
  rule(:array)              { space? >> str('[') >> space? >> value_list.maybe >> space? >> str(']') >> space?}

  rule(:json)               { value.as('value') >> (space? >> str(',') >> value.as('value')).repeat }
  root(:json)
end

# I've changed your doc to be a list of JSON values
doc = '[

        { "foo":
            {"bar":"foo",
                "bar": [
                    {"foo":"bar", "foo":"bar"}
                ]
            }
        }

    ],

{"foo":"bar"},{"foo":"bar"}'

puts JSONParser.new.parse(doc)[1..-1].map{|value| value["value"]}.join(",")
# => {"foo":"bar"},{"foo":"bar"} 

然而,由于我所知道的,您的文档不是有效的JSON格式,因此您可以更改上述内容...

require 'parslet'

class YourFileParser < Parslet::Parser
  rule(:space)              { match('[\s\n]').repeat(1)}
  rule(:space?)             { space.maybe }
  rule(:digit)              { match('[0-9]') }
  rule(:hexdigit)           { match('[0-9a-fA-F]') }

  rule(:number)             { space? >> str('-').maybe >> 
                                (str('0') | (match('[1-9]') >> digit.repeat)) >> 
                                (str('.') >> digit.repeat).maybe >> 
                                ((str('e')| str('E')) >> (str('+')|str('-')).maybe >> digit.repeat ).maybe }

  rule(:escaped_character)  { str('\\') >> (match('["\\\\/bfnrt]') | (str('u') >> hexdigit.repeat(4,4))) }
  rule(:string)             { space? >> str('"') >> (match('[^\"\\\\]') | escaped_character).repeat >> str('"') }
  rule(:value)              { space? >> (string | number | object | array | str('true') | str('false') | str('null')) }

  rule(:pair)               { string >> str(":") >> value }
  rule(:pair_list)          { (pair|value) >> (space? >> str(',') >> (pair|value)).repeat }
  rule(:object)             { str('{') >> space? >> pair_list.maybe >> space? >> str('}') }

  rule(:value_list)         { (pair|value) >> (space? >> str(',') >> (pair|value)).repeat }
  rule(:array)              { space? >> str('[') >> space? >> value_list.maybe >> space? >> str(']') >> space?}

  rule(:yourdoc)           { (pair|value).as('value') >> (space? >> str(',') >> (pair|value).as('value')).repeat }
  root(:yourdoc)
end

doc = '[

        { "foo":
            {"bar":"foo",
                "bar": {
                    ["foo":"bar", "foo":"bar"]
                }
            }
        }

    ],

"foo":"bar","foo":"bar"'

puts YourFileParser.new.parse(doc)[1..-1].map{|value| value["value"]}.join(",")

0

给你:

string.gsub(/\[.*\]/m, '')

你需要使用m标记来匹配换行符的.。 .*已经贪婪,所以它将匹配之间任何数量的括号。


0

很难确定你想要实现什么,但那看起来像是JSON,所以解析它然后以那种方式操作可能会更容易。


不能改变顺序,必须保持原样。无法更改JSON。 - dt1000

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接