在外部文件中存储字典、正则表达式和变量的最佳方式?

Best way to store dicts, regex and variables in external file?

出于配置目的,如果我将 "easy" 正则表达式存储在 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 和编译。

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

您指定的link是JSON规格。据我所知,它没有说明正则表达式。

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

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

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

SO 上还有其他答案,解释了如何正确 encode/decode 正则表达式作为有效 JSON,例如: Escaping Regex to get Valid JSON

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

  • 您可以将 JSON 用于字典、正则表达式和变量吗?
  • JSON理想吗?
    • 取决于您的用例
    • What is JSON and why would I use it?

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

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 用于关注点分离和可读性。

如果您将字典存储在 .py 文件中,只要可以找到该文件,您就可以直接导入变量 in your PYTHONPATH or you use a 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\=')}