Похоже, что эти .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, что и регулярное выражение, но более медленно и подробно.