Применить управляющие символы к строке - 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 доступен здесь.

Другие вопросы по тегам