Применить управляющие символы к строке - Python
Я пытаюсь применить управляющие символы, такие как '\x08 \x08', которые должны удалить прецедентный символ, к строке (двигаться назад, писать пробел, двигаться назад)
Например, когда я набираю в консоли Python:
s = "test\x08 \x08"
print s
print repr(s)
Я получаю в моем терминале:
tes
'test\x08 \x08'
Я ищу функцию, скажем "функция", которая будет "применять" управляющие символы к моей строке:
v = function("test\x08 \x08")
sys.stdout.write(v)
sys.stdout.write(repr(v))
поэтому я получаю "чистую" строку без управляющих символов:
tes
tes
Я понимаю, что в терминале эта часть обрабатывается клиентом, так что, возможно, есть способ получить отображаемую строку, используя основные функции Unix
echo -e 'test\x08 \x08'
cat file.out # control char are here handled by the client
>> tes
cat -v file.out # which prints the "actual" content of the file
>> test^H ^H
1 ответ
На самом деле, ответ был немного сложнее, чем простое форматирование.
Каждый символ, отправляемый процессом в терминал, может рассматриваться как переход в конечном автомате (FSM). Состояние этого автомата приблизительно соответствует отображаемому предложению и положению курсора, но есть много других переменных, таких как размеры терминала, текущая последовательность управления, которая вводится *, режим терминала (например: режим VI / классическая консоль BASH), и т.п.
Хорошую реализацию этого FSM можно увидеть в исходном коде pexpect.
Чтобы ответить на мой вопрос, не существует базовой "функции" unix, которая может форматировать строку в соответствии с тем, что отображается в терминале, поскольку такая функция специфична для терминала, который выводит выходные данные процесса, и вам придется переписать полный терминал, чтобы обрабатывать каждый возможный символ и последовательность управления.
Однако мы сами можем реализовать простой. Нам нужно определить FSM с начальным состоянием:
- отображаемая строка: "" (пустая строка)
- положение курсора: 0
и переходы (ввод символов):
- любой буквенно-цифровой / пробельный символ: заменяет сам символ в позиции курсора (или добавляет, если его нет) и увеличивает позицию курсора
\x08
шестнадцатеричный код: уменьшает позицию курсора
и накорми его струной.
Решение Python
def decode(input_string):
# Initial state
# String is stored as a list because
# python forbids the modification of
# a string
displayed_string = []
cursor_position = 0
# Loop on our input (transitions sequence)
for character in input_string:
# Alphanumeric transition
if str.isalnum(character) or str.isspace(character):
# Add the character to the string
displayed_string[cursor_position:cursor_position+1] = character
# Move the cursor forward
cursor_position += 1
# Backward transition
elif character == "\x08":
# Move the cursor backward
cursor_position -= 1
else:
print("{} is not handled by this function".format(repr(character)))
# We transform our "list" string back to a real string
return "".join(displayed_string)
И пример
>>> decode("test\x08 \x08")
tes
Примечание о контрольных последовательностях
Последовательность управления ANSI - это набор символов, которые действуют как переход в состояние (дисплей / курсор / режим терминала /...) терминала. Это можно рассматривать как уточнение нашего состояния FSM и переходов с большим количеством суб-состояний и суб-переходов.
Например: когда вы нажимаете клавишу UP в классическом терминале Unix (например, VT100), вы фактически вводите последовательность управления: ESC 0 A
где ESC
это шестнадцатеричный код \x1b
, ESC
переходит в режим ESCAPE и возвращается в нормальный режим после A.
Некоторые процессы интерпретируют эту последовательность как движение положения вертикального курсора (VI), другие - как движение назад в истории (BASH): это полностью зависит от программы, которая обрабатывает ввод.
Тем не менее, та же последовательность может использоваться в процессе вывода, но, скорее всего, она будет перемещать курсор вверх по экрану: это зависит от реализации терминала.
Хороший список последовательностей управления ANSI доступен здесь.