Как уменьшите значения в строках в 2 раза, а количество строк увеличить в 2 раза?
Есть текстовый файл с таким содержимым:
Sleep 96 ms
Move 4 0
Sleep 96 ms
Move 12 8
Как разделить всё на 2 (значения четные по умолчанию), но увеличив количество строк в 2 раза (сохранив исходную сумму значений) и привести это к такому виду и такому порядку и сохранить в этот же или отдельный файл:
Sleep 48 ms
Move 2 0
Sleep 48 ms
Move 2 0
Sleep 48 ms
Move 6 4
Sleep 48 ms
Move 6 4
Начал искать выход через парсинг значений
re.findall('[0-9]+', txt_data)
Но в общем уперся в стену, умные люди помогите :) p.s. на python конечно :)
Ответы (2 шт):
Если делать регулярками, то заменять надо полностью по 2 строки:
(Sleep\s+)(\d+)(\s*\w+(\r?\n)Move\s+)(\d+)(\s+)(\d+)(\r?\n|$)
Т. е. метчимся на каждую пару строк полностью порезанную на группы:
- Sleep с пробелами
- Длительность sleep
- Необязательные пробелы, единицы измерения, и move с пробелами
-
- Внутри этой группы ещё ловим группу с переводом строки
- Значение x
- Пробелы
- Значение y
- Перевод строки или конец строки
А потом из этого считаем новые значения и собираем желаемую строку. Группа с переводом строки нужна на случай, если файл не завершается переводом строки: нам в любом случае надо вставлять перевод, поскольку мы из одного блока делаем 2, а значит его надо где-то взять в соответствующем входному файлу виде.
Вот реализация на js:
console.log(`Sleep 96 ms
Move 4 0
Sleep 96 ms
Move 12 8`.replace(
/(Sleep\s+)(\d+)(\s*\w+(\r?\n)Move\s+)(\d+)(\s+)(\d+)(\r?\n|$)/g,
(m, t1, s, t2, br, x, t3, y, t4) => {
s /= 2
x /= 2
y /= 2
var part = `${t1}${s}${t2}${x}${t3}${y}`
return part + br + part + t4
}
))
Если хочется удостовериться, что заменяется весь текст, можно сделать что-то такое. Добавить к регулярке возможность сметчится на 1 любой символ если не удалось выделить блок. В таком случае мы попадаем в функцию замены с этой последней группой и можем кинуть исключение. Специфика регулярок в js позволит оставлять пустые строки между блоками, но на мой взгляд, это не страшно. А вот если действительно что-то не распарсится, то будет исключение.
console.log(`Sleep 96 ms
Move 4 0
Sleep 96 ms
Move 12 8`.replace(
/(Sleep\s+)(\d+)(\s*\w+(\r?\n)Move\s+)(\d+)(\s+)(\d+)(\r?\n|$)|(.)/g,
(m, t1, s, t2, br, x, t3, y, t4, fail) => {
if (fail) throw new Error("Failed to parse")
s /= 2
x /= 2
y /= 2
var part = `${t1}${s}${t2}${x}${t3}${y}`
return part + br + part + t4
}
))
import re
txt = """
Sleep 96 ms
Move 4 0
Sleep 96 ms
Move 12 8
"""
text = re.sub(
# Убираем пустые строки
r'^\n',
'',
re.sub(
# Ищем числа
r'\d+',
# Меняем их на их значения приведенные к int деленные на 2
lambda x: str(int(x.group(0)) // 2),
txt
),
flags=re.S
)
print(
# Повторяем текст 2 раза
# Здесь возможны варианты но это от исходника зависит
text * 2
)
Sleep 48 ms
Move 2 0
Sleep 48 ms
Move 6 4
Sleep 48 ms
Move 2 0
Sleep 48 ms
Move 6 4
UPD:
Ну вот такой апдейт получился
import re
def chunks(iterable, chunk_size: int):
for i in range(0, len(iterable), chunk_size):
yield iterable[i:i + chunk_size]
def string_mod(string: str):
return re.sub(
# Убираем пустые строки
r'^\n',
'',
re.sub(
# Ищем числа
r'\d+',
lambda x: '{:.0f}'.format(int(x.group(0)) / 2),
string
),
flags=re.S
)
txt = """
Sleep 96 ms
Move 4 0
Sleep 96 ms
Move 12 8
"""
new_text_lines = []
# Вытащил в отдельную переменную
# рулит тем, какое количество строк нужно повторять
block_length = 2
# Тоже в отдельной переменной
# отвечает за количество повторений блока
factor = 2
for part in chunks(txt.strip('\n').split('\n'), block_length):
new_text_lines += map(string_mod, part * factor)
print(
'\n'.join(new_text_lines)
)
Sleep 48 ms
Move 2 0
Sleep 48 ms
Move 2 0
Sleep 48 ms
Move 6 4
Sleep 48 ms
Move 6 4