【问题标题】:What is the most Pythonic way to loop over a list where certain entries act as headers for subsequent entries?在某些条目充当后续条目的标题的列表中循环的最 Pythonic 方式是什么?
【发布时间】:2021-06-17 15:16:41
【问题描述】:

作为记录 CLI 工具命令的系统输出的结果...

import subprocess
list_operations_cmd = 'cloud_cli_tool --list'
all_operations_sysout = subprocess.check_output(list_operations_cmd, shell=True)

我得到一个如下所示的字符串:

Project: foo foo foo (Environment: PRODUCTION)
  ipsum dolor sit
  Excepteur sint occaecat
  POST aliquip ex ea
Project: foo foo foo (Environment: DEVELOPMENT)
  ipsum dolor sit
  Excepteur sint occaecat
  POST aliquip ex ea
Project: bar (Environment: PRODUCTION)
  velit esse cillum
  occaecat cupidatat

我想把它变成一个看起来像这样的数据结构,以促进我的工作对我正在编写这个 Python 脚本以向系统用户公开的命令接口的参数进行输入清理。

[
 {
  project: "foo foo foo",
  environment: "PRODUCTION",
  operation: "ipsum dolor sit"
 },
 {
  project: "foo foo foo",
  environment: "PRODUCTION",
  operation: "Excepteur sint occaecat"
 },
 {
  project: "foo foo foo",
  environment: "PRODUCTION",
  operation: "POST aliquip ex ea"
 },
 {
  project: "foo foo foo",
  environment: "DEVELOPMENT",
  operation: "ipsum dolor sit"
 },
 {
  project: "foo foo foo",
  environment: "DEVELOPMENT",
  operation: "Excepteur sint occaecat"
 },
 {
  project: "foo foo foo",
  environment: "DEVELOPMENT",
  operation: "POST aliquip ex ea"
 },
 {
  project: "bar",
  environment: "PRODUCTION)",
  operation: "velit esse cillum"
 },
 {
  project: "bar",
  environment: "PRODUCTION)",
  operation: "occaecat cupidatat"
 }
]

如您所见,项目/环境的变化可以通过不带缩进的换行来检测;可以通过换行符后跟两个空格来检测记录的更改。项目/环境行充当以下行的“标题”,直到检测到新的“项目/环境行”。

我知道我可以只 .splitlines() 整个事情并开始一次循环一行,缓存内容并 if-then-elsing ......但感觉可能有一种比 Pythonic 更:

proj_env_pattern = r'^Project: (.*) \(Environment: (.*)\)$'
all_operations_list = all_operations_sysout.splitlines()
for line in all_operations_list[:20]:
    is_header = False
    if not line.startswith('  '):
        is_header = True
        project = re.search(proj_env_pattern, line, re.IGNORECASE).group(1)
        print project
        # TO DO:  code...
    # TO:  code...

Linux 上的 Python 2.7.5;无法安装任何新模块。


更新:

感谢@fsimonjetz 的提示。如果你想让它成为答案,我可以接受并关闭。

代码现在比我做的要整洁得多:

import re
import subprocess

def get_all_operations():
    list_operations_cmd = 'cloud_cli_tool --list'
    proj_env_pattern = r'^(.*) \(Environment: (.*)\)$'
    all_operations_list = []
    all_projects = subprocess.check_output(list_operations_cmd, shell=True).split('Project: ')
    for project in all_projects[1:]:
        project_lines = project.splitlines()
        project_search = re.search(proj_env_pattern, project_lines[0])
        for line in project_lines[1:]:
            all_operations_list.append({'project': project_search.group(1), 'environment': project_search.group(2), 'operation': line.lstrip()})
    return all_operations_list

print get_all_operations()

【问题讨论】:

  • 到目前为止您尝试过什么?什么不工作? @k..
  • 好吧,我知道我可以.splitlines() 并一次循环遍历它,并执行各种手动 if-else 操作以查找从一行到下一行的变化,但我不太擅长“更聪明”的做事方式,只是好奇是否有人有任何“更聪明”、“更 Pythonic”的想法。更新的问题。
  • 那就写一些吧。不要担心你的代码有多 Pythonic,直到你有一些可以工作的东西。
  • 如果输入是正则,你甚至不需要正则表达式。可以先.split('Project:') 整个字符串将所有片段放入一个列表中,然后循环它以提取其他部分。
  • @fsimonjetz -- 聪明 -- 谢谢你,这是我知道别人会建议的技巧!!!想让它成为答案吗?

标签: python python-2.7 text-parsing


【解决方案1】:

感谢@fsimonjetz 的提示。如果您想将其作为答案,我可以接受,但请在 cmets 中添加我根据您的建议实施的内容,这样对于浏览要回答的问题的人来说,这不再是没有答案的。

解决方案是利用所有“标题行”以 Project: 开头的幸运事实,并将整个 sysout 字符串分解为带有 .split('Project: ') 的每个标题子字符串。对于每个子字符串,进一步解析是通常的正则表达式,.splitlines(),&[1:] 列表切片。

import re
import subprocess

def get_all_operations():
    list_operations_cmd = 'cloud_cli_tool --list'
    proj_env_pattern = r'^(.*) \(Environment: (.*)\)$'
    all_operations_list = []
    all_projects = subprocess.check_output(list_operations_cmd, shell=True).split('Project: ')
    for project in all_projects[1:]:
        project_lines = project.splitlines()
        project_search = re.search(proj_env_pattern, project_lines[0])
        for line in project_lines[1:]:
            all_operations_list.append({'project': project_search.group(1), 'environment': project_search.group(2), 'operation': line.lstrip()})
    return all_operations_list

print get_all_operations()

【讨论】:

    猜你喜欢
    • 2013-01-21
    • 1970-01-01
    • 2022-11-30
    • 2022-11-28
    • 2014-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-17
    相关资源
    最近更新 更多