使用文件第一行的字符串重命名目录中的'.tbl'文件。

问题描述 投票:0回答:1

我有一个目录,里面全是'.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
python file-rename batch-rename astropy
1个回答
1
投票

出现这个错误的原因是 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的情况。


0
投票

好像是这样 .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])

这和你刚才做的类似,但更健壮一些(同时返回键和值)。 但你可以看到这比正则表达式版本更复杂。 它实际上或多或少地实现了与正则表达式完全相同的逻辑,但更加缓慢和啰嗦。

© www.soinside.com 2019 - 2024. All rights reserved.