我有一个目录,里面全是'.tbl'文件。文件设置如下。
\STAR_ID = "HD 74156"
\DATA_CATEGORY = "行星径向速度曲线"
\NUMBER_OF_POINTS = "82"
\时间参考帧 = "JD"
\最小日期 = "2453342.23249"
\DATE_UNITS = "天"
\MAXIMUM_DATE = "2454231.60002"
....
我需要用STAR_ID重命名目录中的每个文件。所以在这种情况下,文件名将是'HD 74156.tbl'。
我已经能够做到这一点的约600个文件的20。我不知道为什么它不会继续通过其余的文件。
我目前的代码是:"HD 74156.tbl"。
for i in os.listdir(path):
with open(i) as f:
first_line = f.readline()
system = first_line.split('"')[1]
new_file = system + ".tbl"
os.rename(file, new_file)`
而错误信息是:
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-37-5883c060a977> in <module>
3 with open(i) as f:
4 first_line = f.readline()
----> 5 system = first_line.split('"')[1]
6 new_file = system + ".tbl"
7 os.rename(file, new_file)
IndexError: list index out of range
出现这个错误的原因是 first_line.split('"')
正在返回一个少于2个项目的列表,你可以试试
first_line_ls = first_line.split('"')
if len(first_line_ls) > 1:
system = first_line_ls[1]
else:
#other method
这段代码可以帮助你防止错误,并处理file_line str少于2的情况。
好像是这样 .tbl
文件并不像你所希望的那样统一。 如果这一行。
----> 5 system = first_line.split('"')[1]
在某些文件上失败了,那是因为它们的第一行没有按照你所期望的格式化,正如 @Leo Arad 指出的那样。 你也要确保你的 其实 使用 STAR_ID
字段。 也许这些文件通常会把所有的字段按同样的顺序排列(作为一个旁观者,这些 .tbl
文件? 是什么软件出来的? 我从来没有见过),但是既然你已经发现了其他格式不一致的地方,那么安全总比遗憾好。
我可能会写一个小辅助函数来解析这个文件中的字段。 它只需要一行,然后返回一个 (key, value)
字段的元组。 如果该行看起来不像是一个有效的字段,它将返回 (None, None)
:
import re
# Dissection of this regular expression:
# ^\\ : line begins with \
# (?P<key>\w+) : extract the key, which is one or more letters, numbers or underscores
# \s*=\s* : an equal sign surrounding by any amount of white space
# "(?P<value>[^"]*)" : extract the value, which is between a pair of double-quotes
# and contains any characters other than double-quotes
# (Note: I don't know if this file format has a mechanism for escaping
# double-quotes inside the value; if so that would have to be handled as well)
_field_re = re.compile(r'^\\(?P<key>\w+)\s*=\s*"(?P<value>[^"]*)"')
def parse_field(line):
# match the line against the regular expression
match = _field_re.match(line)
# if it doesn't match, return (None, None)
if match is None:
return (None, None)
else:
# return the key and value pair
return match.groups()
现在打开你的文件,在所有的行上循环,一旦你找到了,就进行重命名。STAR_ID
. 如果没有,就打印一个警告(这和你的代码大部分是一样的,只是有一些轻微的变化)。
for filename in os.listdir(path):
filename = os.path.join(path, filename)
star_id = None
# NOTE: Do the rename outside the with statement so that the
# file is closed; on Linux it doesn't matter but on Windows
# the rename will fail if the file is not closed first
with open(filename) as fobj:
for line in fobj:
key, value = parse_field(line)
if key == 'STAR_ID':
star_id = value
break
if star_id is not None:
os.rename(filename, os.path.join(path, star_id + '.tbl'))
else:
print(f'WARNING: STAR_ID key missing from {filename}', file=sys.stderr)
如果你对正则表达式不熟悉(实际上,谁会不熟悉呢?),最好学习一下基础知识,因为这是一个非常有用的工具。 然而,这种格式足够简单,你可以像你一样使用简单的字符串解析方法来摆脱。 不过我还是会稍微加强一下,以确保你确实得到了STAR_ID字段。 就像这样。
def parse_field(line):
if '=' not in line:
return (None, None)
key, value = [part.strip() for part in line.split('=', 1)]
if key[0] != '\\':
return (None, None)
else:
key = key[1:]
if value[0] != '"' or value[-1] != '"':
# still not a valid line assuming quotes are required
return (None, None)
else:
return (key, value.split('"')[1])
这和你刚才做的类似,但更健壮一些(同时返回键和值)。 但你可以看到这比正则表达式版本更复杂。 它实际上或多或少地实现了与正则表达式完全相同的逻辑,但更加缓慢和啰嗦。