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
|
Show 5 more comments
4 Answers
Reset to default 3the \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.
mystr
? – Mr. Polywhirl Commented Mar 14 at 21:08/r
the only thing or do you want full terminal emulation ?! – Ahmed AEK Commented Mar 14 at 21:14print()
appliesstr()
to each of its parameters. Typing an expression at the Python prompt appliesrepr()
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) whoserepr()
could possibly beSerial-Number: 12345
(since that's not a valid Python expression), so the only way to achieve your desired result would be fornewStr
to be an instance of a user-defined class with__repr__()
defined in an unusual way. – jasonharper Commented Mar 14 at 21:31terminal
, since we fot that those windows are software version of physical terminals. Which, themselves, were replacement of printers. Hence the functionprint
, notdisplay
, 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