【问题标题】:Best way to store dicts, regex and variables in external file?在外部文件中存储字典、正则表达式和变量的最佳方式?
【发布时间】:2019-06-20 16:09:11
【问题描述】:

出于配置目的,如果我将“简单”的正则表达式存储在 JSON 文件中并将其加载到我的 Python 程序中,它就可以正常工作。

{
    "allow": ["\/word\/.*"],
    "follow": true
},

如果我在 JSON 文件中存储更复杂的正则表达式,相同的 Python 程序会失败。

{
    "allow": ["dcp\=[0-9]+\&dppp\="],
    "follow": true
},

这是加载我的 JSON 文件的代码:

src_json = kw.get('src_json') or 'sources/sample.json'
self.MY_SETTINGS = json.load(open(src_json))

而且错误通常是相同的,将我的在线搜索指向一个事实,即regular expressions should not be stored in JSON 文件。

json.decoder.JSONDecodeError: Invalid \escape: line 22 column 38 (char 801)

YAML 文件似乎有 similar limitations,所以我猜我不应该这样下去。

现在,我已将我的表达式存储在一个单独的文件中的字典中:

mydict = {"allow": "com\/[a-z]+(?:-[a-z]+)*\?skid\="}

并从我的程序文件中加载它:

exec(compile(source=open('expr.py').read(), filename='expr.py', mode='exec'))

print(mydict)

这对我有用并且对我来说很好 - 但它看起来有点......特别......带有 exec 和 compile。

有什么理由不这样做吗? 有没有更好的方法将复杂的数据结构和正则表达式存储在我可以在我的程序代码中打开/使用的外部文件中?

【问题讨论】:

标签: python json python-3.x configuration-files


【解决方案1】:

您指出的链接是 JSON 规范。据我所知,它没有说任何关于正则表达式的内容。

您似乎正在做的是采用一个有效的正则表达式并将其粘贴到您的 JSON 文件中以供(重新)使用。这并不总是有效,因为必须对某些内容进行转义才能使 JSON 有效。

但是,有一种简单的方法可以将正则表达式插入 JSON 文件,使用适当的转义符,方法是制作一个小型 Python 程序,将正则表达式作为命令行参数,然后 @ 987654321@ JSON 文件,或者使用新的正则表达式加载更新转储文件。

【讨论】:

    【解决方案2】:

    首先,正则表达式可以存储为 JSON,但需要存储为有效的 JSON。这就是示例中您的JSONDecodeError 的原因。

    这里还有其他答案,解释了如何将正则表达式正确编码/解码为有效的 JSON,例如: Escaping Regex to get Valid JSON

    现在,您的问题的其他部分开始涉及更多最佳实践和意见。

    如您所见,您当然可以声明和使用其他文件中的变量:

    test_regex.py

    my_dict = {'allow': 'com\\/[a-z]+(?:-[a-z]+)*\\?skid\\='}
    

    script.py

    from test_regex import mydict
    mydict
    {'allow': 'com\\/[a-z]+(?:-[a-z]+)*\\?skid\\='}
    

    但是,这是一个完全不同的感觉用例。在我们的 JSON 示例中,信息以一种我们期望它更容易配置的方式设置 - 可以使用不同的 JSON 文件(可能用于不同的环境配置),每个文件都有不同的正则表达式。在此示例中,我们不假设可配置性,而是使用 test_regex 来分离关注点和可读性。

    【讨论】:

      【解决方案3】:

      如果您将字典存储在 .py 文件中,则可以直接导入变量,只要该文件可以找到 in your PYTHONPATH 或您使用 relative import。

      例如,如果我创建了一个名为 expr.py 的 .py 文件,而 PYTHONPATH 包含它所在的文件夹。

      文件的内容(和你的例子一样):

      mydict = {"allow": "com\/[a-z]+(?:-[a-z]+)*\?skid\="}
      

      然后我可以从解释器或其他脚本运行它

      >>> from expr import mydict
      >>> mydict
      {'allow': 'com\\/[a-z]+(?:-[a-z]+)*\\?skid\\='}
      

      除非我在这里遗漏了一些东西,否则无需搞砸open() 和exec。我使用这种方法来存储正则表达式,因为您可以直接存储 re.compile 对象。

      如果我将文件更改为:

      import re
      mydict = {"allow": re.compile(r"com\/[a-z]+(?:-[a-z]+)*\?skid\=")}
      

      我能做到:

      >>> from expr import mydict
      >>> print(mydict)
      {'allow': re.compile('com\\/[a-z]+(?:-[a-z]+)*\\?skid\\=')}
      >>> print(mydict["allow"].pattern)
      com\/[a-z]+(?:-[a-z]+)*\?skid\=
      >>> print(mydict["allow"].match("com/x-x?skid="))
      <_sre.SRE_Match object; span=(0, 13), match='com/x-x?skid='>
      

      如果文件有大量的正则表达式,则脚本名称下的变量的自动排序也有助于组织:

      文件:

      import re
      mydict = {"allow": re.compile(r"com\/[a-z]+(?:-[a-z]+)*\?skid\=")}
      easydict = {"allow": re.compile(r"\/word\/.*"), "follow": True}
      complexdict = {"allow": re.compile(r"dcp\=[0-9]+\&dppp\="), "follow": True}
      

      翻译:

      >>> import expr
      >>> print(expr.easydict["allow"].pattern)
      \/word\/.*
      >>> print(expr.complexdict["allow"].match("dcp=11&dppp="))
      <_sre.SRE_Match object; span=(0, 12), match='dcp=11&dppp='>
      >>> print(expr.mydict)
      {'allow': re.compile('com\\/[a-z]+(?:-[a-z]+)*\\?skid\\=')}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-06
        • 1970-01-01
        相关资源
        最近更新 更多