最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Get Python string value as printed by "print()" - Stack Overflow

programmeradmin2浏览0评论

Suppose I have a string as follows (after parsing some stdout):

>>> mystr
'--More-- \r         \rSerial-Number: 12345'

I notice that print() function automatically processes the \r characters, essentially getting rid of the entire "--More--" part, like this:

>>> print(mystr)
Serial-Number: 12345

How can I achieve the same result in a variable? In other words, I'd like to get a string variable newStr, so that:

>>> newStr
Serial-Number: 12345

Suppose I have a string as follows (after parsing some stdout):

>>> mystr
'--More-- \r         \rSerial-Number: 12345'

I notice that print() function automatically processes the \r characters, essentially getting rid of the entire "--More--" part, like this:

>>> print(mystr)
Serial-Number: 12345

How can I achieve the same result in a variable? In other words, I'd like to get a string variable newStr, so that:

>>> newStr
Serial-Number: 12345
Share Improve this question asked Mar 14 at 21:05 Dmitry PeretsDmitry Perets 1,12310 silver badges20 bronze badges 10
  • 1 Also, where is your initial assignment of mystr? – Mr. Polywhirl Commented Mar 14 at 21:08
  • 5 print doesn't actually do that, it's your terminal that does it .... you want to emulate how the terminal processes strings .... is /r the only thing or do you want full terminal emulation ?! – Ahmed AEK Commented Mar 14 at 21:14
  • 1 print() applies str() to each of its parameters. Typing an expression at the Python prompt applies repr() to it, which is generally more detailed, and generally takes the form of a Python expression that would reproduce the value. There is no standard type (that I'm aware of) whose repr() could possibly be Serial-Number: 12345 (since that's not a valid Python expression), so the only way to achieve your desired result would be for newStr to be an instance of a user-defined class with __repr__() defined in an unusual way. – jasonharper Commented Mar 14 at 21:31
  • 1 As Ahmed said, python has no idea what appears on your screen (or printer. Probably you are using a terminal emulator, often called terminal, since we fot that those windows are software version of physical terminals. Which, themselves, were replacement of printers. Hence the function print, not display, even in languages that came to existence years after people stopped using printers for that. But still, those \r, \n, etc, are still printers control character. Put the carriage back to the beginning of the line. Feed the paper one line forward. Ring a bell. Etc. – chrslg Commented Mar 14 at 23:28
  • 1 I guess, you could implement a whole "virtual terminal" that renders in a string buffer, and shows the end result. Since some terminals (like Terminator) are implemented in python, you could even steal their code to do that. But even doing so, it wouldn't ensure that what is in the string is what would be displayed on the screen. That is terminal dependent. On your screen you'd have 1 kind of terminal. Your "virtual terminal" would be another kind of terminal. And I don't think I have ever seen 2 different terminals behaving exactly the same way, even when they claim to use a common standard – chrslg Commented Mar 14 at 23:42
 |  Show 5 more comments

4 Answers 4

Reset to default 3

the \r is called a carriage return, and when it is encountered in some buffer, it moves the cursor back to the start of the line and continues printing from the beginning of the line. So what really is happening in your print is:

  • it actaully writes --More-- to the buffer
  • it encounters the \r and moves the cursor to the beginning of the line (deleting what was on the line before)
  • it starts writing all the spaces
  • then it hits another \r and starts over again
  • finally, it writes the part you're interested in to the buffer and that is all that is flushed to STOUT.

if you want to do this in some variable, all you have to do is split on \r and get the last piece of your string. I would do something like this:

myStr = '--More-- \r         \rSerial-Number: 12345'
*_, newStr = myStr.rsplit('\r', maxsplit=1)

this splits the string on its last \r, then assigns newStr to that segment, throwing out all the other information. the unpacking *_ allows this to work even if no \r exists.

EDIT: thank you @globglogabgalab for pointing out my error. in some IDEs (like PyCharm), the carriage return will clear the string before writing the new characters, but this is not a python behavior. Typically, the carriage return will just move the cursor to the beginning of the string, and replace old characters with new, leaving the ends of the old lines. this is how to better emulate the actual STOUT behavior if you want to keep the characters from longer previous strings:

>>> from functools import reduce
...
>>> myStr = 'This is the Longest String\rShorter str\rending'
>>> newStr = str(reduce(lambda x, y: y + x[len(y):], myStr.split('\r'), ''))
>>> print(newStr)
'endingr str Longest String'

step-through logic:

1: the reduce iterator starts as ''

2: 'This is the Longest String' is added to the string from the beginning.

3: 'Shorter String' is added from the beginning, but since it's shorter, it doesn't replace all of the characters. the string is now 'Shorter str Longest String'

4: 'ending' is added to the string as the beginning. the string is now 'endingr str Longest String'.

5: str(...) runs the iterator

You can use:

def removeCarriageReturn( string ):
    if "\r" in string:
        index = string.index( "\r" )
        while True:
            if "\r" in string[ index + 1 : ]:
                aux = string.index( "\r", index + 2 )
                if aux == None:
                    break
            else:
                break
            index = aux
        return string[ index + 1 : ]
    return string

Surely the code can be improved, this is just a first approximation.

Explanation:

If the received string does not contain "\r" we return it, if it does, we first look for its index, then we enter the while and look for a new possible occurrence, if it exists, we update index otherwise, we exit the loop and return the obtained string.

You just need to split the string on carriage return then isolate the last token in the generated list as follows:

mystr = "--More-- \r         \rSerial-Number: 12345"

myvar = mystr.split("\r")[-1]
print(myvar)

Output:

Serial-Number: 12345

Note:

This will also work if there are no carriage returns in the source string

OK, as pointed out by several people above, the trick was not actually done by print(), it was done by the terminal itself to which print() was sending the string. I didn't realize that part, now it makes more sense. Thanks to all who pointed that out!

So, in the end, I will just treat it as a usual string manipulation case. Something like this:

i = mystr.rfind('\r')
newstr = mystr[i+1:]

It also works when the string doesn't contain '\r', because rfind() returns -1 in that case.

发布评论

评论列表(0)

  1. 暂无评论