Переименовать файлы .tbl в каталоге, используя строку из первой строки файла python - PullRequest
0 голосов
/ 26 мая 2020

У меня есть каталог, заполненный файлами .tbl. Файл настроен следующим образом:

\ STAR_ID = "HD 74156"

\ DATA_CATEGORY = "Pl anet Кривая радиальной скорости"

\ NUMBER_OF_POINTS = "82 "

\ TIME_REFERENCE_FRAME =" JD "

\ MINIMUM_DATE =" 2453342.23249 "

\ DATE_UNITS =" дней "

\ MAXIMUM_DATE =" 2454231.60002 " 1015 *

....

Мне нужно переименовать каждый файл в каталоге, используя STAR_ID,

, поэтому в этом случае имя файла будет 'HD 74156.tbl.'

Мне удалось сделать это примерно для 20 из ~ 600 файлов.

Я не уверен, почему он не будет продолжен для остальных файлов.

Мой текущий код:

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

Ответы [ 2 ]

1 голос
/ 26 мая 2020

Эта ошибка возникает из-за того, что 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 голосов
/ 28 мая 2020

Похоже, что эти .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()

Теперь откройте файл l oop по всем строкам и выполните переименование, как только найдете 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])

Это похоже на то, что вы делали, но немного более надежно (и возвращает ключ, а также значение). Но вы можете видеть, что это более сложная версия, чем версия с регулярным выражением. На самом деле он более или менее реализует тот же лог c, что и регулярное выражение, но более медленно и подробно.

...