6

This sample code prints the representation of a line from a file. It allows its contents to be viewed, including control characters like '\n', on a single line—so we refer to it as the "raw" output of the line.

print("%r" % (self.f.readline()))

The output, however, appears with ' characters added to each end which aren't in the file.

'line of content\n'

How to get rid of the single quotes around the output?
(Behavior is the same in both Python 2.7 and 3.6.)

martineau
  • 119,623
  • 25
  • 170
  • 301
TMWP
  • 1,545
  • 1
  • 17
  • 31
  • 2
    This is what this format specifier was created to do. Why would you want to remove the quotes? They're there to show the bounds of the string. – ForceBru Mar 23 '17 at 20:02
  • 1
    use `str.strip("'")` or `[1:-1]` slicing. – Jean-François Fabre Mar 23 '17 at 20:03
  • 1
    The "r"` specified doesn't stand for "raw", it stands for "representation", which means the Python representation of the object. Since it's a string in this case, these are always quoted. – martineau Mar 23 '17 at 20:05
  • That's not a "raw specifier". `%r` says to call `repr` on the thing being substituted. – user2357112 Mar 23 '17 at 20:06
  • good to know. Had not heard of `repr` so googled it after reading your answer. This is more detail on that: http://stackoverflow.com/questions/1436703/difference-between-str-and-repr-in-python – TMWP Mar 23 '17 at 20:10
  • I don't like that dup because it needs the string _after_ the repr, but that's done in the `%r`. You need to take the `repr` of the string, strip the quotes and then `%s` print it. `print("%s" %(repr(self.f.readline())[1:-1]))`. – tdelaney Mar 23 '17 at 20:15
  • That makes sense. – TMWP Mar 23 '17 at 20:22
  • @martineau - If this post stays at zero it will be deleted to prevent it negatively impacting something about how this site works. (users can lose the ability to post questions if the site detects too many zero-voted posts). I thought this might be a useful example to others even though I realized the answer rather quickly. I figure you agree or you would not have edited it, but if you like something enough to edit it, you really should vote it up so you don't lose the points when it then gets deleted. This community is sometimes friendly and sometimes hostile (depends on the day). – TMWP Mar 23 '17 at 20:26
  • @martineau - On meta - it has been discussed that points are taken away if the question you edited is deleted because they don't want to encourage "polishing turds". If you edit a question you do not think is worthy of an up-vote, then you are not making the site better. You are polishing what you believe to be turds. And if the poster deletes it to prevent zeroes from taking away from the right to post questions (which can happen), then you wasted your time and lose any points awarded for your efforts. Editing a question that you do not like is also sending a mixed message to the poster – TMWP Mar 24 '17 at 13:07
  • do what you think is right. But just had to offer that 2 cents – TMWP Mar 24 '17 at 13:08
  • Let's keep in mind the only thing I did in my edit was remove one word from the title (and add a question mark at the end). Hardly what I'd call "polishing a turd". I didn't do it to make it a more interesting question. Removing the word is just because that's one of my [pet-peeves](https://meta.stackexchange.com/questions/19190/should-questions-include-tags-in-their-titles/130208#130208). – martineau Mar 24 '17 at 13:26
  • Related question, [Escape special characters in a Python string - Stack Overflow](https://stackoverflow.com/questions/4202538/escape-special-characters-in-a-python-string) – user202729 Dec 23 '22 at 08:41

2 Answers2

8

%r takes the repr representation of the string. It escapes newlines and etc. as you want, but also adds quotes. To fix this, strip off the quotes yourself with index slicing.

print("%s" %(repr(self.f.readline())[1:-1]))

If this is all you are printing, you don't need to pass it through a string formatter at all

print(repr(self.f.readline())[1:-1])

This also works:

print("%r" %(self.f.readline())[1:-1])
Martin Tournoij
  • 26,737
  • 24
  • 105
  • 146
tdelaney
  • 73,364
  • 6
  • 83
  • 116
  • Or add an extra pair of parentheses: `print(("%r" %(self.f.readline()))[1:-1])`. – ForceBru Mar 23 '17 at 20:20
  • 1
    There's no reason to involve `"%s"` at all; you can just print the result of slicing the `repr` directly. – user2357112 Mar 23 '17 at 20:22
  • @user2357112 - I am following user's pattern assuming this is just example code and the real format may be bigger. But you are right, you could do `print(repr(self.f.readline())[1:-1])` in this case. – tdelaney Mar 23 '17 at 20:23
  • `print(("%r" % (self.f.readline())).strip("'")` works but is fragile. If your format is larger (e.g., "line: %r"), it fails. If it isn't larger, then - as mentioned by @user2357112 - you don't need the formatter at all. Python is free to use `"..."` instead of `'...'` when printing `repr` so `[1:-1]` is safer. – tdelaney Mar 23 '17 at 20:44
  • just did an edit and did not realize it would need peer review. If the edit is accepted, I will be accepting this answer. I think it is the best so far but needed a tweak to make it complete. – TMWP Mar 23 '17 at 20:47
  • @TMWP - I don't particularly like that third option in the edit `print("%r" %(self.f.readline())[1:-1])`. As mentioned, there is no need to pass through a formatter if the format is simply `"%r"`. The second option is already the better choice. – tdelaney Mar 23 '17 at 21:08
  • @tdelaney TMWP's suggested alternative is also wrong nonsense, cuts off actual string content and then adds the quotes. – Stefan Pochmann Mar 23 '17 at 21:10
  • @StefanPochmann - you are right! You'd need more parens `print(("%r" %(f.readline()))[1:-1])`. – tdelaney Mar 23 '17 at 21:15
  • What no one has stated in this debate is why this matters. Is `repr()` more efficient when used directly then if a formatter is involved? Is there any notice-able overhead to using `%r` or is this all "i like this", "I don't like that" ... I am guessing this is the case but other than "like" & "don't like" no one on this thread actually justified their reasoning with logic. Nonetheless, good recommendations were made and my coding solution is using indexing and not the answer I originally posted, and then deleted when better answers showed up on here. – TMWP Mar 24 '17 at 13:21
  • `repr` is trivially faster than `%r` (`%r` calls `repr`) but there is no real technical reason why its bad. To me, a format string shouldn't need reformatting after its done. Usually the formatter pretties things up (may add leading zeros or something). In my view, `%r` doesn't do what you want and so you shouldn't use it then fix it. Do your customization first. IMHO! – tdelaney Mar 24 '17 at 15:31
4

Although this approach would be overkill, in Python you can subclass most, if not all, of the built-in types, including str. This means you could define your own string class whose representation is whatever you want.

The following illustrates using that ability:

class MyStr(str):
    """ Special string subclass to override the default representation method
        which puts single quotes around the result.
    """
    def __repr__(self):
        return super(MyStr, self).__repr__().strip("'")

s1 = 'hello\nworld'
s2 = MyStr('hello\nworld')

print("s1: %r" % s1)
print("s2: %r" % s2)

Output:

s1: 'hello\nworld'
s2: hello\nworld
martineau
  • 119,623
  • 25
  • 170
  • 301
  • Though you are right that this is overkill, this is intriguing piece of code for someone new to Python to learn from. – TMWP Mar 24 '17 at 13:10
  • did not realize I could vote on more than one answer. – TMWP Mar 24 '17 at 13:23
  • oddly - you took the time to look up code and answer this question as did one other. It started debates in the comments on the best solution and I found out some useful stuff in the process that others new to Python may benefit from and yet the question itself is still holding at zero. Despite your work on it, do you not like the question either? – TMWP Mar 24 '17 at 13:30
  • Or just overwrite the `__repr__` method in `MyStr` with ```def __repr__(self): return self.__str__()``` – fhgd Jul 21 '20 at 19:43
  • @fhgd: What you suggest is **not** equivalent as it would result in the substrings `hello` and `world` being printed on separate lines. – martineau Jul 21 '20 at 23:06
  • @martineau: Oh, this case I missed. Thank you! – fhgd Jul 22 '20 at 07:41