如果单词与模式匹配,则用字符包围任何单词

时间:2014-07-02 09:53:22

标签: python regex

我有一个像这样的输入字符串:

'{ query: { and: [ { and: [ { _t: "Manifest" }, { or: [ { and: [ { _i: { gt: "53b2616fe4b028359ac3fea4" } } ] } ] }, { _s: "active" } ] }, { ENu_v: { elemMatch: { EOJ_v: { in: [ "*", "Production", "QA    " ] } } } } ] }, orderby: { _i: 1 } } '

我想将其更改为字典。

a = '{ query: { and: [ { and: [ { _t: "Manifest" }, { or: [ { and: [ { _i: { gt: "53b2616fe4b028359ac3fea4" } } ] } ] }, { _s: "active" } ] }, { ENu_v: { elemMatch: { EOJ_v: { in: [ "*", "Production", "QA    " ] } } } } ] }, orderby: { _i: 1 } } '

json.loads(a)

但是这会引发异常 query应为"query"and应为"and" 等等。

所以我想将string之类的所有字符串更改为"string",我该如何实现?

2 个答案:

答案 0 :(得分:3)

使用re.sub

In [1]: import re

In [2]: text = '{ query: { and: [ { and: [ { _t: "Manifest" }, { or: [ { and: [ { _i: { gt: "53b2616fe4b028359ac3fea4" } } ] } ] }, { _s: "active" } ] }, { ENu_v: { elemMatch: { EOJ_v: { in: [ "*", "Production", "QA    " ] } } } } ] }, orderby: { _i: 1 } } '

In [3]: re.sub('(\w+):', r'"\1":', text)
Out[3]: '{ "query": { "and": [ { "and": [ { "_t": "Manifest" }, { "or": [ { "and": [ { "_i": { "gt": "53b2616fe4b028359ac3fea4" } } ] } ] }, { "_s": "active" } ] }, { "ENu_v": { "elemMatch": { "EOJ_v": { "in": [ "*", "Production", "QA    " ] } } } } ] }, "orderby": { "_i": 1 } } '

请注意,您必须使用原始字符串文字(或转义\1作为\\1)作为替换文本,否则您将无法获得预期的输出。


我假设您的文字不包含“奇怪”的内容,例如:

  • 值内的冒号(例如{a: "some:string"};此解决方案不保留"some:string"
  • 包含嵌套结构的复杂字符串(例如{a: "{b : \"hello\"}"}

如果这些假设不成立,你必须实际解析文本,并且你不能单独使用正则表达式来安全地转换它。

ast模块和codegen第三方模块可以轻松操作此类数据。例如,您可以创建一个NodeTransformer子类,例如:

class QuoteNames(ast.NodeTransformer):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._inside_dict = False
    def visit_Name(self, node):
        if self._inside_dict:
            return ast.copy_location(ast.Str(node.id), node)
        else:
            return node
    def visit_Dict(self, node):
        self._inside_dict = True
        self.generic_visit(node)
        self._inside_dict = False
        return node

并将其用作:

import ast, codegen
codegen.to_source(QuoteNames().visit(ast.parse(text))

但是,您的示例文本不是语法上有效的文字,因为某些括号不匹配(在您的示例中可能是错误),有一些字符串值缺少结尾引号而您无法使用{{1} }或and标识符。

如果您可以修复格式以匹配python语法,那么上述解决方案比使用正则表达式的解决方案更强大。但是,如果这不可能,你必须为它编写自己的解析器,或者寻找能够做到这一点的第三方模块。

答案 1 :(得分:1)

您可以匹配以下内容:

'(\w+):'

并替换为:

'"\1":'

其中\1是第一个被捕获的组。

您可以在此处看到它:DEMO