2010-02-02 20 views
16

के साथ तारों के लिए पाइथन में सही स्ट्रिंग लंबाई प्राप्त करना मेरे पास कुछ पायथन कोड है जो स्वचालित रूप से एक अच्छे कॉलम प्रारूप में डेटा का एक सेट प्रिंट करेगा, जिसमें उपयुक्त ASCII एस्केप अनुक्रमों को रंग के विभिन्न टुकड़ों को रंग देने के लिए स्वचालित रूप से प्रिंट किया जाएगा पठनीयता के लिए डेटा।एएनएसआई रंग कोड

मैं अंततः प्रत्येक पंक्ति को एक सूची के रूप में प्रदर्शित करने के साथ समाप्त होता हूं, प्रत्येक आइटम एक कॉलम होता है जो अंतरिक्ष-गद्देदार होता है ताकि प्रत्येक पंक्ति पर एक ही कॉलम हमेशा एक ही लंबाई हो। दुर्भाग्यवश जब मैं वास्तव में इसे प्रिंट करने के लिए जाता हूं, तो सभी कॉलम लाइन अप नहीं होते हैं। मुझे लगता है इस ASCII भागने दृश्यों के साथ क्या करना है - क्योंकि len समारोह पहचान करने के लिए नहीं लगता है इन:

>>> a = '\x1b[1m0.0\x1b[0m' 
>>> len(a) 
11 
>>> print a 
0.0 

और इसलिए, जबकि प्रत्येक स्तंभ len के अनुसार एक ही लंबाई है, वे वास्तव में ही नहीं हैं स्क्रीन पर मुद्रित जब लंबाई।

क्या कोई रास्ता है (बचने वाली स्ट्रिंग लेने के लिए नियमित रूप से अभिव्यक्तियों के साथ कुछ हैकर करने के लिए सहेजें) और मुद्रित लंबाई क्या है, इसलिए मैं स्पेस पैड उचित तरीके से कर सकता हूं? शायद स्ट्रिंग पर वापस "प्रिंट" करने के लिए कुछ तरीका और उस की लंबाई की जांच करें?

+3

ये वास्तव में "एएनएसआईआई" रंग कोड हैं, न कि "ASCII", जैसा कि एएनएसआई रंग टर्मिनल पर दिखाया जाएगा, या ANSI.SYS ड्राइवर का उपयोग कर पीसी पर। – PaulMcG

उत्तर

9

pyparsing विकी एएनएसआई भागने दृश्यों पर मिलान के लिए इस helpful expression में शामिल हैं:

ESC = Literal('\x1b') 
integer = Word(nums) 
escapeSeq = Combine(ESC + '[' + Optional(delimitedList(integer,';')) + 
       oneOf(list(alphas))) 

यहां किसी भागने-अनुक्रम-स्ट्रिपर में इस प्रकार करें:

from pyparsing import * 

ESC = Literal('\x1b') 
integer = Word(nums) 
escapeSeq = Combine(ESC + '[' + Optional(delimitedList(integer,';')) + 
       oneOf(list(alphas))) 

nonAnsiString = lambda s : Suppress(escapeSeq).transformString(s) 

unColorString = nonAnsiString('\x1b[1m0.0\x1b[0m') 
print unColorString, len(unColorString) 

प्रिंट:

0.0 3 
+0

तकनीकी रूप से सीमित सूची में तार भी हो सकते हैं, हालांकि यह संभावना नहीं है कि आप कभी भी ऐसे अनुक्रम को पूरा करेंगे। यह भी देखें http://stackoverflow.com/questions/1833873/python-regex-escape-characters/1834669#1834669 – bobince

+1

ओएच, मुझे यह नहीं पता! मेरे युवाओं में, हमने उन वीटी 100 के नृत्य को बनाया, अपने एलईडी को चमकते हुए, अपने स्क्रॉल क्षेत्रों को बदल दिया, बोल्ड रिवर्स वीडियो में डबल-हाई-डबल-वाइड फोंट का उत्पादन किया - आह, वे कौन सा प्रमुख दिन थे ... – PaulMcG

+0

धन्यवाद, जो पूरी तरह से काम करता है ! मैं उम्मीद कर रहा था कि बस कुछ blahlibrary.unescape() विधि कहीं मैं देख रहा था, लेकिन यह अगली सबसे अच्छी बात है! –

1

ANSI_escape_code में देख रहे हैं, आपके एक्सपैम्प में अनुक्रम ले ग्राफिक रेंशन (शायद बोल्ड) का चयन करें।

CUrsor स्थिति (CSI n ; m H) अनुक्रम के साथ कॉलम स्थिति को नियंत्रित करने का प्रयास करें। इस तरह, पिछले पाठ की चौड़ाई वर्तमान कॉलम स्थिति को प्रभावित नहीं करती है और स्ट्रिंग चौड़ाई के बारे में चिंता करने की आवश्यकता नहीं है।

यदि आप यूनिक्स को लक्षित करते हैं, तो बेहतर विकल्प curses module window-objects का उपयोग कर रहा है।

window.addnstr([y, x], str, n[, attr])

(y, x) गुण attr के साथ, कुछ भी पहले से प्रदर्शन पर अधिलेखन में स्ट्रिंग str के सबसे n पात्रों पर पेंट: उदाहरण के लिए, एक तार के साथ स्क्रीन पर स्थित किया जा सकता है ।

+0

धन्यवाद - मैं शापों पर एक नज़र डालेगा। –

3

मुझे दो चीजों को समझ में नहीं आता है।

(1) यह आपका कोड है, आपके नियंत्रण में। आप अपने डेटा में एस्केप अनुक्रम जोड़ना चाहते हैं और फिर उन्हें फिर से बाहर करना चाहते हैं ताकि आप अपने डेटा की लंबाई की गणना कर सकें ?? से पहले भागने के दृश्य जोड़कर पैडिंग की गणना करने के लिए यह बहुत आसान लगता है। मैं क्या खो रहा हूँ?

मान लीजिए कि किसी भी बचने के दृश्य कर्सर की स्थिति को बदलते हैं। यदि वे करते हैं, तो वर्तमान में स्वीकृत उत्तर वैसे भी काम नहीं करेगा।

मान लीजिए कि आपके पास string_data नाम की एक सूची में प्रत्येक कॉलम (भागने अनुक्रम जोड़ने से पहले) के लिए स्ट्रिंग डेटा है और पूर्व निर्धारित कॉलम चौड़ाई width नाम की एक सूची में हैं। कुछ इस तरह का प्रयास करें: ओपी की टिप्पणी के बाद

temp = [] 
for colx, text in enumerate(string_data): 
    npad = width[colx] - len(text) # calculate padding size 
    assert npad >= 0 
    enhanced = fancy_text(text, colx, etc, whatever) # add escape sequences 
    temp.append(enhanced + " " * npad) 
sys.stdout.write("".join(temp)) 

अद्यतन "" "कारण मैं उन्हें निकाल देते हैं और लंबाई के बाद स्ट्रिंग रंग कोड होता है गणना करना चाहते हैं, क्योंकि सभी डेटा प्रोग्राम के रूप में बनाया गया है है। मेरे पास रंगीन विधियों का एक गुच्छा है और मैं इस तरह कुछ डेटा बना रहा हूं: str = "% s /% s /% s"% (ग्रीन (डेटा 1), नीला (डेटा 2), लाल (डेटा 3)) यह होगा तथ्य के बाद पाठ को रंगना बहुत मुश्किल हो। ""

यदि डेटा अपने स्वयं के स्वरूपण के साथ प्रत्येक टुकड़े से बना है, तो आप अभी भी प्रदर्शित लंबाई और पैड की गणना कर सकते हैं।

BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(40, 48) 
BOLD = 1 

def render_and_pad(reqd_width, components, sep="/"): 
    temp = [] 
    actual_width = 0 
    for fmt_code, text in components: 
     actual_width += len(text) 
     strg = "\x1b[%dm%s\x1b[m" % (fmt_code, text) 
     temp.append(strg) 
    if temp: 
     actual_width += len(temp) - 1 
    npad = reqd_width - actual_width 
    assert npad >= 0 
    return sep.join(temp) + " " * npad 

print repr(
    render_and_pad(20, zip([BOLD, GREEN, YELLOW], ["foo", "bar", "zot"])) 
    ) 

यदि आपको लगता है कि कॉल विराम चिह्न द्वारा बोझ है, तो आप की तरह कुछ कर सकता है::

BOLD = lambda s: (1, s) 
BLACK = lambda s: (40, s) 
# etc 
def render_and_pad(reqd_width, sep, *components): 
    # etc 

x = render_and_pad(20, '/', BOLD(data1), GREEN(data2), YELLOW(data3)) 

(2) मुझे समझ नहीं आता यहाँ एक समारोह जो करता है एक सेल की सामग्री के लिए कि आप आपूर्ति-के-पायथन नियमित अभिव्यक्ति किट का उपयोग क्यों नहीं करना चाहते हैं। नहीं "hackery" ("hackery" है कि मैं के बारे में पता कर रहा हूँ के किसी भी संभावित अर्थ के लिए) शामिल है:

>>> import re 
>>> test = "1\x1b[a2\x1b[42b3\x1b[98;99c4\x1b[77;66;55d5" 
>>> expected = "12345" 
>>> # regex = re.compile(r"\x1b\[[;\d]*[A-Za-z]") 
... regex = re.compile(r""" 
...  \x1b  # literal ESC 
...  \[  # literal [ 
...  [;\d]* # zero or more digits or semicolons 
...  [A-Za-z] # a letter 
...  """, re.VERBOSE) 
>>> print regex.findall(test) 
['\x1b[a', '\x1b[42b', '\x1b[98;99c', '\x1b[77;66;55d'] 
>>> actual = regex.sub("", test) 
>>> print repr(actual) 
'12345' 
>>> assert actual == expected 
>>> 

अद्यतन ओपी की टिप्पणी "" "मैं अभी भी पॉल के जवाब पसंद करते हैं, क्योंकि यह अधिक संक्षिप्त है" "के बाद "

अधिक संक्षिप्त क्या है? रेगेक्स समाधान आपके लिए पर्याप्त नहीं है:

# === setup === 
import re 
strip_ANSI_escape_sequences_sub = re.compile(r""" 
    \x1b  # literal ESC 
    \[  # literal [ 
    [;\d]* # zero or more digits or semicolons 
    [A-Za-z] # a letter 
    """, re.VERBOSE).sub 
def strip_ANSI_escape_sequences(s): 
    return strip_ANSI_escape_sequences_sub("", s) 

# === usage === 
raw_data = strip_ANSI_escape_sequences(formatted_data) 

??

+0

उत्तर जॉन के लिए धन्यवाद। कारण मैं उन्हें बाहर निकालना चाहता हूं और लंबाई * की गणना * स्ट्रिंग के बाद रंग कोड है क्योंकि सभी डेटा प्रोग्रामेटिक रूप से बनाया गया है। मेरे पास रंगीन विधियों का एक गुच्छा है और मैं इस तरह कुछ डेटा बना रहा हूं: str = "% s /% s /% s"% (ग्रीन (डेटा 1), नीला (डेटा 2), लाल (डेटा 3)) तथ्य के बाद पाठ को रंगना बहुत मुश्किल होगा।हैकरी के लिए, शायद मुझे जो कहना चाहिए था, "मुझे लगता है कि यह एक हल समस्या है और मुझे सही पुस्तकालय नहीं मिल रहा है"। मान लीजिए, लेकिन मैं अभी भी पॉल का जवाब पसंद करता हूं क्योंकि यह अधिक संक्षिप्त है। –

+0

ठीक है, मैं इस पर काट दूंगा। मैं देखता हूं कि आप लंबाई के साथ गणना करते समय क्या कर रहे हैं। आपके द्वारा प्रस्तावित समाधान काफी काम नहीं करता है, सिर्फ इसलिए कि समय से पहले वांछित कॉलम लंबाई जानने के लिए आपको उस कॉलम के सेल में संग्रहीत करने के लिए सबसे बड़ी स्ट्रिंग की लंबाई पता है। फिर भी, मुझे नहीं लगता कि इस बारे में कुछ लिखना बहुत कठिन होगा और इस तथ्य के बाद रंग अनुक्रमों को अलग करने की आवश्यकता नहीं थी। –

+1

रेगेक्स टिप्पणी के लिए, मुझे पाइथन के समर्थन में निर्मित कोई समस्या नहीं है। मैं आमतौर पर रेगेक्स पार्सिंग करने से दूर शर्मिंदा हूं क्योंकि इसे गड़बड़ करना और कुछ किनारे के मामले को भूलना आसान है। उन लोगों के प्रश्नों की अनदेखी सूची देखें जो लोगों के सबूत के लिए एचटीएमएल के साथ regexes का उपयोग करने की कोशिश कर रहे हैं। या, बस पॉल की पोस्ट पर टिप्पणी देखें, जो बताती है कि जो उन्होंने प्रदान किया वह वास्तव में गैर-रंग नियंत्रण कोडों के लिए खाता नहीं है। उस ने कहा, जब रंगों के बारे में केवल चिंतित है, तो यह दिखाया गया है कि यह बहुत सरल है। –

0

तुम सिर्फ कुछ कोशिकाओं के लिए रंग जोड़ रहे हैं [के बाद @Nick पर्किन्स ने बताया कि यह काम नहीं किया सही किया कोड से ऊपर], यह सबसे सरल सिर्फ उम्मीद सेल चौड़ाई (5 छिपा 9 को जोड़ने के लिए है रंग चालू करने के लिए अक्षर, 4 इसे बंद करने के लिए), उदाहरण के लिए

import colorama # handle ANSI codes on Windows 
colorama.init() 

RED = '\033[91m' # 5 chars 
GREEN = '\033[92m' # 5 chars 
RESET = '\033[0m' # 4 chars 

def red(s): 
    return RED + s + RESET 
def green(s): 
    return GREEN + s + RESET 
def redgreen(v, fmt, sign=1): 
    s = fmt.format(v) 
    return red(s) if (v*sign)<0 else green(s) 

header_format = "{:9} {:5} {:>8} {:10} {:10} {:9} {:>8}" 
row_format = "{:9} {:5} {:8.2f} {:>19} {:>19} {:>18} {:>17}" 
print header_format.format("Type","Trial","Epsilon","Avg Reward","Violations", "Accidents","Status") 
# loop 
    trial_type = "Testing " if testing else "Training" 
    avg_reward = redgreen(float(reward)/nsteps, "{:.2f}") 
    violations = redgreen(actions[1] + actions[2], "{:d}", -1) 
    accidents = redgreen(actions[3] + actions[4], "{:d}", -1) 
    status = green("On time") if d['success'] else red("Late") 
    print row_format.format(trial_type, trial, epsilon, avg_reward, violations, accidents, status)