2016-12-14 2 views
0

Я следующий вывод XTERM в:регулярного выражения, ASCII маскирующим Пайтона в теги

text = '\x1b[0m\x1b[01;32mattr\x1b[0m\n\x1b[01;36mawk\x1b[0m\n\x1b[01;32mbasename\x1b[0m\n\x1b[01;32mbash\n\x1b[0many text' 

я знал, что \x1b[0m, чтобы удалить все текстовые атрибуты и \x1b[01 если для жирного текста, \x1b[32m зеленый текст и \x1b[01;32m является полужирный зеленый текст. Итак, как я могу передать эти escape-символы в свои собственные теги? Как это:

\x1b[0m\x1b[01;32mattr --> <bold><green>attr</bold></green> 

Я хочу, чтобы мой text переменная становится это:

text = '<bold><green>attr</bold></green>\n<bold><cyan>awk</bold></cyan>\n<bold><green>basename</bold></green>\n<bold><green>bash</bold></green>\nanytext' 

ответ

1
import re 

text = '\x1b[0m\x1b[01;32mattr\x1b[0m\n\x1b[01;36mawk\x1b[0m\n\x1b[01;32mbasename\x1b[0m\n\x1b[01;32mbash\n\x1b[0many text' 

# dictionary mapping text attributes to tag names 
fmt = {'01':'bold', '32m':'green', '36m': 'cyan'} 
# regex that gets all text attributes, the text and any potential newline 
groups = re.findall('(\n?)\\x1b\[((?:(?:0m|32m|01|36m);?)+)([a-zA-Z ]+)', text) 
# iterate through the groups and build your new string 
xml = [] 
for group in groups: 
    g_text = group[2] # the text itself 
    for tag in group[1].split(';'): # the text attributes 
     if tag in fmt: 
      tag = fmt[tag] 
     else: 
      continue 
     g_text = '<%s>%s</%s>' %(tag,g_text,tag) 
    g_text = group[0] + g_text # add a newline if necessary 
    xml.append(g_text) 
xml_text = ''.join(xml) 

print(xml_text) 

<green><bold>attr</bold></green> 
<cyan><bold>awk</bold></cyan> 
<green><bold>basename</bold></green> 
<green><bold>bash</bold></green> 
any text 

Для демонстрации на регулярных выражений смотрите по этой ссылке: Debuggex Demo

В настоящее время регулярное выражение предполагает, что вы только имеют альфа-символы или пробелы в фактическом тексте, но не стесняйтесь изменять эту группу ([a-zA-Z ]+) в конце регулярного выражения, чтобы включить другой символ которые вы можете иметь в своем тексте.

Кроме того, я предполагаю, что у вас больше атрибутов текста, чем полужирный, зеленый и голубой. Вам нужно будет обновить словарь fmt другими вашими атрибутами и их сопоставлениями.

EDIT

@Caaarlos запросило в комментариях (ниже), чтобы сохранить код AnSi как на выходе, если он не появляется в fmt словаре:

import re 

text = '\x1b[0m\x1b[01;32;35mattr\x1b[0;7m\n\x1b[01;36mawk\x1b[0m\n\x1b[01;32;47mbasename\x1b[0m\n\x1b[01;32mbash\n\x1b[0many text' 

fmt = {'01':'bold', '32':'green', '36': 'cyan'} 

xml = [] 
active_tags = [] 
for group in re.split('\x1b\[', text): 
    if group.strip(): 
     codes, text = re.split('((?:\d+;?)+)m', group)[1:] 
     not_found = [] 
     for tag in codes.split(';'): 
      if tag in fmt: 
       tag = fmt[tag] 
       text = '<%s>%s' %(tag,text) 
       active_tags.append(tag) 
      elif tag == '0': 
       for a_tag in active_tags[::-1]: 
        text = '</%s>%s' %(a_tag,text) 
       active_tags = [] 
      else: 
       not_found.append(tag) 
     if not_found: 
      text = '\x1b[%sm%s' %(';'.join(not_found), text) 
     xml.append(text) 
xml_text = ''.join(xml) 

print(repr(xml_text)) 

'\x1b[35m<green><bold>attr\x1b[7m</bold></green>\n<cyan><bold>awk</bold></cyan>\n\x1b[47m<green><bold>basename</bold></green>\n<green><bold>bash\n</bold></green>any text' 

Обратите внимание, что отредактированный код выше также обрабатывает случаи, когда тег не закрывается непосредственно после текста.

+0

Спасибо, Бунджи, он работает правильно. Но, когда у меня нет шаблона в fmt, я хочу, чтобы моя текстовая переменная продолжала иметь escape-последовательность ascii (цели отладки). Например, если есть не '36m' шаблон, я хочу, чтобы мой окончательный вывод будет: атр \ X1B [01; 36mawk базовое Баш любой текст – Caaarlos

+0

@Caaarlos, ответ был обновлен с помощью редактирования, который обрабатывает коды, не найденные в fmt. Кроме того, он обрабатывает случаи, когда тег не должен закрываться непосредственно после текста. – bunji