2

Is it possible to get width of a string as it appears on the terminal?

Assuming the terminal supports ansi-escpace sequences, this

s = u"\u001b[31m" +"foo" + u"\u001b[0m"
print(len(s))
print(s)

will print

12
foo

with the second line in red. Given only the already concatenated s, is there an easy way to get the width of it (3 in this case)?

Also \t is counted as 1 character, but thats easier to account for.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • This may be helpful: https://stackoverflow.com/a/22632060/1692260. or `string.printable` if ASCII only. – Aaron May 22 '20 at 14:40
  • 1
    It seems like you're effectively asking how to strip the ansi-escape sequences from a string, which has already been answered here: https://stackoverflow.com/q/14693701/984421. – ekhumoro May 22 '20 at 15:00
  • @ekhumoro thanks that looks very promising. Unfortunately I have to leave it for now. – 463035818_is_not_an_ai May 22 '20 at 15:02
  • [_Printed length of a string in python_](https://stackoverflow.com/q/14889454/674039), which didn't have any particularly promising answers either.. – wim May 22 '23 at 22:26

1 Answers1

1

Here is what I put together using the links in the comments,

from re import compile

def line_width(s, tab_width=4):
    if '\n' in s:
        raise ValueError('String contains mutliple lines.')
    # https://stackoverflow.com/q/14693701/12035739
    ansi_be_gone = compile(r'(?:\x1B[@-_]|[\x80-\x9F])[0-?]*[ -/]*[@-~]')
    s = ansi_be_gone.sub('', s)
    return len(s) + s.count('\t') * (tab_width - 1)

Now,

s = u"\u001b[31m" +"foo" + u"\u001b[0m"
print(len(s))
print(s)

Prints 3 to the console.

scribe
  • 673
  • 2
  • 6
  • 17