【问题标题】:Extract text from a config file [duplicate]从配置文件中提取文本[重复]
【发布时间】:2021-09-30 17:53:34
【问题描述】:

我正在使用一个配置文件来通知我的 Python 脚本一些键值,用于针对网站对用户进行身份验证。

我有三个变量:URL、用户名和 API 令牌。

我创建了一个配置文件,每个键位于不同的行,所以:

url:<url string>
auth_user:<user name>
auth_token:<API token>

我希望能够将关键字之后的文本提取到变量中,同时去除行尾存在的任何“\n”。目前我正在这样做,它可以工作但看起来很笨拙:

with open(argv[1], mode='r') as config_file:
    lines = config_file.readlines()

for line in lines:
    url_match = match('jira_url:', line)
    if url_match:
        jira_url = line[9:].split("\n")[0]
    user_match = match('auth_user:', line)
    if user_match:
        auth_user = line[10:].split("\n")[0]
    token_match = match('auth_token', line)
    if token_match:
        auth_token = line[11:].split("\n")[0]

谁能提出更优雅的解决方案?具体来说,是 ... = line[10:].split("\n")[0] 行对我来说似乎很笨重。

我也有点困惑,为什么我不能在 for 循环中重用我的匹配对象,并且必须为每个配置项创建新的匹配对象。

【问题讨论】:

标签: python


【解决方案1】:

您可以使用 .yml 文件并通过 yaml.load() 函数读取值:

import yaml
with open('settings.yml') as file:
     settings = yaml.load(file, Loader=yaml.FullLoader)

现在您可以访问 settings["url"] 等元素

【讨论】:

    【解决方案2】:

    如果格式始终为&lt;tag&gt;:&lt;value&gt;,您可以通过在冒号处拆分行并填写自定义字典来轻松解析它:

    config_file = open(filename,"r")
    lines = config_file.readlines()
    config_file.close()
    
    settings = dict()
    for l in lines:
        elements = l[:-1].split(':')
        settings[elements[0]] = ':'.join(elements[1:])
    

    因此,您会得到一个字典,其中标签作为键,值作为值。然后,您可以在您的程序中参考这些字典条目。 (例如:如果您需要 auth_token,只需致电 settings["auth_token"]

    【讨论】:

    • 谢谢,但是当其中一个值是包含冒号的 URL 时,这不起作用。键左侧的一些值也可能如此!
    • 我写的代码处理键右边的冒号没有任何问题。这就是":".join( 的用途。它将错误地拆分的元素重新连接在一起。但是如果冒号左边和的值可能包含冒号,那么它就是一个功能失调的配置文件。那么,你怎么知道哪个冒号分隔键和值呢?
    【解决方案3】:

    如果你可以为配置文件添加 1 行,configparser 是不错的选择

    https://docs.python.org/3/library/configparser.html

    [1] 配置文件:1.cfg

    [DEFAULT]     # configparser's config file need section name
    url:<url string>
    auth_user:<user name>
    auth_token:<API token>
    

    [2] python 脚本

    import configparser
    
    config = configparser.ConfigParser()
    config.read('1.cfg')
    print(config.get('DEFAULT','url'))
    print(config.get('DEFAULT','auth_user'))
    print(config.get('DEFAULT','auth_token'))
    

    [3] 输出

    <url string>
    <user name>
    <API token>
    

    configparser 的方法也很有用

    你不能保证配置文件总是完整的

    【讨论】:

    • 谢谢,我试试看!
    【解决方案4】:

    您已经有了几个很好的答案,但我想退后一步,就您将来如何解决这些问题提供一些指导。获得快速答案有时会让您无法理解这些人最初是如何知道答案的。

    当您缩小时,让我印象深刻的第一件事是您的任务是使用文件为您的程序提供配置。软件具有一次解决、随处使用的显着特性。至少 40 年来,配置文件一直是一个值得解决的问题,因此您可以打赌,您不需要自己解决这个问题。已经解决意味着有人已经弄清楚了所有的小问题和边缘案例,比如剥离线的结尾和处理预期的输入。当然,挑战在于了解已经存在的解决方案。如果你没有花 40 年时间揭开电脑的外壳,看看它们是如何运转的,那么很难“只知道”。因此,您可能会在 Google 上寻找“配置文件格式”之类的东西。

    这将带您进入地球上最流行的配置文件系统之一 - INI 文件。现在和 30 年前一样有用,而且作为奖励,看起来与您的示例配置文件并没有太大的不同。然后你可能会搜索“read INI file in Python”之类的,遇到configparser就基本完成了。

    或者您可能会看到,在过去 30 年的某个时候,YAML 成为了更流行的选择,您不知道吗,PyYAML 将为您完成大部分工作。

    但这些都不能让您更好地使用 Python 从文本文件中提取数据。所以放大一点,你想知道如何提取文本文件中的部分行。同样,这个问题是一个古老的问题,如果你要了解这个问题(而不是仅仅得到解决方案),你会知道这被称为 解析 并且经常涉及 标记化。如果你做一些研究,比如说“在 python 中解析一个文本文件”,你就会了解不管是哪种语言都可以使用的通用技术,例如循环遍历行并依次拆分每一行。

    再放大一步,您希望将新行从字符串末尾剥离,这样它就不会包含在您的值中。再一次,这不是一个新问题,使用正确的关键字,您可以挖掘出被广泛采用的解决方案。这通常被称为“chomping”或“stripping”,通过一些仔细的搜索词,你会找到rstrip() 和朋友,而不必做一些尴尬的事情,比如拆分 '\n' 字符。

    您的最后一个问题是关于重新使用匹配对象。这更难研究。但同样,“解决方案”不一定会告诉你哪里出错了。您需要记住的是,for 循环中的语句是顺序的。要仔细考虑它们,您应该逐个在脑海中执行它们,并想象正在发生的事情。每次调用 match,它要么返回None,要么返回一个 Match 对象。除了检查if 语句中的真实性外,您从不使用该对象。下次你调用 match 时,你会使用不同的参数来调用,所以你会得到一个新的 Match 对象(或None)。因此,您根本不需要将对象保留在周围。你可以这样做:

    if match('jira_url:', line):
        jira_url = line[9:].split("\n")[0]
    if match('auth_user:', line):
        auth_user = line[10:].split("\n")[0]
    

    等等。不仅如此,如果第一个if 触发了,那么您就不需要再次调用match - 它肯定不会触发相同line 的任何其他匹配。所以你可以这样做:

    if match('jira_url:', line):
        jira_url = line[9:].rstrip()
    elif match('auth_user:', line):
        auth_user = line[10:].rstrip()
    

    等等。

    但是你可以开始思考 - 为什么要在冒号上进行所有这些匹配,然后才在冒号处手动拆分字符串?你可以这样做:

    tokens = line.rstrip().split(':')
    if token[0] == 'jira_url':
        jira_url = token[1]
    elif token[0] == 'auth_user':
        auth_user = token[1]
    

    如果您继续进行这些改进(还有很多事情要做!),最终您将重新编写 configparse,但至少您会了解为什么使用现有的通常是个好主意实用的图书馆!

    【讨论】:

    • 感谢您稍微光顾的回复:-)。我很清楚我是 Python 的新手,但拥有丰富的开发经验。并且(我发现)学习如何发展的最好方法不是花很长时间研究围绕某种情况的所有事情,而是找到有效的东西然后理解它。但是感谢您最终提供的帮助,它非常有用,现在已添加到我迅速增长的 Python 知识中!
    猜你喜欢
    • 2014-07-11
    • 1970-01-01
    • 1970-01-01
    • 2012-08-31
    • 2019-12-16
    • 2019-06-29
    • 2013-06-29
    • 1970-01-01
    相关资源
    最近更新 更多