Как я могу проанализировать цветовые коды терминала Linux?

#python #linux #terminal

#python #linux #терминал

Вопрос:

Я пытаюсь отобразить цветной текст из файла в curses приложении python. Файл содержит 24-битные коды цветового экранирования, такие как: ^[[48;2;255;255;255m^[[38;2;255;255;255mA . Мне нужно перебрать файл и сгенерировать список кортежей, содержащий такие кортежи: ((background: r, g, b), (foreground: r, g, b), char) . Вот код, который я пробовал до сих пор. Он пытается найти все байты 0x27 и проанализировать их, однако, похоже, это не работает, и не только потому, что это не особенно безопасно / масштабируемо / ремонтопригодно. Как я могу проанализировать цветовые коды в таком файле? Есть ли библиотека? Как я могу улучшить этот код, если нет библиотеки?

 def read_until(char, data, pos):
    """read from a bytes-like object starting at `pos` until the target character is found"""
    start = pos
    while data[pos] != char: pos  = 1
    return data[start:pos], pos

def makeData(data):
    assert type(data) == bytes

    out = []
    pos = 0
    bg = (0, 0, 0)
    fg = (255, 255, 255)

    while pos < len(data):
        if data[pos] == 27: #start of the escape sequence
            pos  = 2 # 2 to ignore the `[` char
            if data[pos:pos   2] == b"0m": #reset character, just ignore it
                continue
            first_num, pos = read_until(ord(";"), data, pos)
            second_num, pos = read_until(ord(";"), data, pos   1) #  1 for the `;` char

            r, pos = read_until(ord(";"), data, pos   1)
            g, pos = read_until(ord(";"), data, pos   1)
            b, pos = read_until(ord("m"), data, pos   1)
            r = int(r)
            g = int(g)
            b = int(b)
            pos  = 1 #skip last `m` char
            if first_num == b"48": #48 means foreground
                fg = (r, g, b)
            elif first_num == b"38": #38 means background
                bg = (r, g, b)
        else:
            out.append((fg, bg, chr(data[pos]))) #use current fg and bg colours with char
            pos  = 1
    return out

with open("file.txt", "rb") as f:
    print("".join([chr(i[2]) for i in makeData(f.read())])) #print without colour codes, to test
  

Ответ №1:

Вы можете использовать регулярное выражение для анализа данных :

 import re
with open("file.txt") as f:
    result = re.findall(r'x1b[48;2;(d );(d );(d )mx1b[38;2;(d );(d );(d )m(.)', f.read())
    print(result)
  

Комментарии:

1. Это хорошее начало, но оно не отличает цвета фона от переднего плана, и мне также нужны фактические символы. Возможно ли это с помощью регулярных выражений?

2. Что такое char ? Это так A ? 48 представляет передний план?

3. Да, A — это символ, а 48 и 38 представляют передний план и фон

4. Отлично! Спасибо!