Python - 用空格分隔行?

Python - line split with spaces?

我确定这是一个基本问题,但我已经花了大约一个小时来解决这个问题,但还是不太明白。我正在解析 smartctl 输出,这是我正在处理的数据示例:

smartctl 5.41 2011-06-09 r3365 [x86_64-linux-2.6.32-39-pve] (local build)
Copyright (C) 2002-11 by Bruce Allen, http://smartmontools.sourceforge.net

=== START OF INFORMATION SECTION ===
Device Model:     TOSHIBA MD04ACA500
Serial Number:    Y9MYK6M4BS9K
LU WWN Device Id: 5 000039 5ebe01bc8
Firmware Version: FP2A
User Capacity:    5,000,981,078,016 bytes [5.00 TB]
Sector Sizes:     512 bytes logical, 4096 bytes physical
Device is:        Not in smartctl database [for details use: -P showall]
ATA Version is:   8
ATA Standard is:  Exact ATA specification draft version not indicated
Local Time is:    Thu Jul  2 11:24:08 2015 EDT
SMART support is: Available - device has SMART capability.
SMART support is: Enabled

我想要实现的是提取设备模型(有些设备只是一个字符串,其他设备,比如这个,是两个词)、序列号、时间和其他几个字段。我假设在冒号之后捕获所有数据是最容易的,但是如何消除可变数量的空格呢?

这是我目前想出的相关代码:

deviceModel = ""
serialNumber = ""
lines = infoMessage.split("\n")
for line in lines:
    parts = line.split()
    if str(parts):
        if parts[0] == "Device Model:     ":
            deviceModel = parts[1]
        elif parts[0] == "Serial Number:    ":
            serialNumber = parts[1]
vprint(3, "Device model: %s" %deviceModel)
vprint(3, "Serial number: %s" %serialNumber)

我不断收到的错误是:

File "./tester.py", line 152, in parseOutput
if parts[0] == "Device Model:     ":
IndexError: list index out of range

我明白了错误的意思(有点),但我不确定范围可能是什么,或者我是否以正确的方式尝试了这个。寻找指导让我朝着正确的方向前进。非常感谢任何帮助。

谢谢!

我猜你的问题是中间的空行。因为,

>>> '\n'.split()
[]

你可以这样做,

>>> f = open('a.txt')
>>> lines = f.readlines()
>>> deviceModel = [line for line in lines if 'Device Model' in line][0].split(':')[1].strip()
# 'TOSHIBA MD04ACA500'
>>> serialNumber = [line for line in lines if 'Serial Number' in line][0].split(':')[1].strip()
# 'Y9MYK6M4BS9K'

我调试它的方法是在每次迭代时打印出 parts。尝试一下,并向我们展示失败时的列表。

编辑:您的问题很可能是@jonrsharpe 所说的。 parts 到达空行时可能是一个空列表,而 str(parts) 将只是 return '[]'True。尝试测试一下。

尝试使用正则表达式:

import re

r = re.compile("^[^:]*:\s+(.*)$")
m = r.match("Device Model:     TOSHIBA MD04ACA500")
print m.group(1)   # Prints "TOSHIBA MD04ACA500"

不确定您使用的是哪个版本 运行,但是在 2.7 上,line.split() 正在逐字拆分行,因此

>>> parts = line.split()
parts = ['Device', 'Model:', 'TOSHIBA', 'MD04ACA500']

您也可以尝试line.startswith()找到您想要的行https://docs.python.org/2/library/stdtypes.html#str.startswith

当拆分 returns 长度为一或零的列表并且您访问第二个元素时,会发生 IndexError。当找不到要拆分的内容(空行)时会发生这种情况。

不需要正则表达式:

deviceModel = ""
serialNumber = ""
lines = infoMessage.split("\n")

for line in lines:
    if line.startswith("Device Model:"):
        deviceModel = line.split(":")[1].strip()
    elif line.startswith("Serial Number:"):
        serialNumber = line.split(":")[1].strip()

print("Device model: %s" %deviceModel)
print("Serial number: %s" %serialNumber)

我认为在这里使用正则表达式会容易得多。

import re

for line in lines:
    # Splits the string into at most two parts
    # at the first colon which is followed by one or more spaces
    parts = re.split(':\s+', line, 1)
    if parts:
        if parts[0] == "Device Model":
            deviceModel = parts[1]
        elif parts[0] == "Serial Number":
            serialNumber = parts[1]

请注意,如果您只关心这两个字段,startswith 可能会更好。

拆分空行时,parts为空列表。 您尝试通过检查一个空列表来适应它,但是您将空列表转换为一个字符串,这会导致您的条件语句为真。

>>> s = []
>>> bool(s)
False
>>> str(s)
'[]'
>>> bool(str(s))
True
>>> 

if str(parts): 更改为 if parts:

许多人会说使用 try/except 块对于 Python

来说是惯用的
for line in lines:
    parts = line.split()
    try:
        if parts[0] == "Device Model:     ":
            deviceModel = parts[1]
        elif parts[0] == "Serial Number:    ":
            serialNumber = parts[1]
    except IndexError:
        pass