字符串中的"\n"无法正常工作

11

我有一个针对我的某种操作系统的小代码:

print("Type your document below.")
print("Press enter to save.")
print("Type \\n for a new line.")
file=input()
print("Enter a file name...")
filename=input()
outFile = open(filename, "w+")
outFile.write(file)
outFile.close()

但是当我运行这个代码(在一个 def 中),比如我输入类似于这样的内容:

foo \n bar

因为从用户那里接收输入时,回车键无法起作用,所以你必须使用 \n。

文件的结果是:

foo \n bar

替代:

foo
bar

在字符串中使用\n可以防止实际上创建一个新行,而不是像Type (new line) for a new line那样。 - Xtreme
3个回答

17

\n 是一种转义序列,只在 字符串字面量 中起作用。 input() 不使用字符串字面量,它接受用户输入的文本并不对其进行任何处理,因此输入 \ 后跟 n 的任何人都会产生一个由两个字符组成的字符串,即反斜杠和字母 n,而不是换行符。

你需要自己处理这类转义序列:

file = file.replace(r'\n', '\n')

在这里我使用了原始字符串字面量来定义一个带有反斜杠\n的文本,原始字符串字面量不支持转义序列。

或者,重复要求用户输入新文件名,直到他们完成为止:

lines = []
print('Type in your document, followed by a blank line:')
while True:
    line = input("> ")
    if not line:
        break
    lines.append(line)
file = '\n'.join(lines)

演示:

>>> lines = []
>>> print('Type in your document, followed by a blank line:')
Type in your document, followed by a blank line:
>>> while True:
...     line = input("> ")
...     if not line:
...         break
...     lines.append(line)
...
> foo
> bar
>
>>> lines
['foo', 'bar']
>>> '\n'.join(lines)
'foo\nbar'

那我该怎么做呢? - Xtreme

12

正如Martijn所解释的,您需要自己处理替换。最简单的方法是使用.replace方法:

>>> print(input('Enter \\n for newline: ').replace('\\n', '\n'))
Enter \n for newline: This is my \nnewline
This is my 
newline

如果你只需要使用转义序列\n,这个方法可以很好地工作,但是如果你需要其他的(例如\t),那么你就需要自己实现。


非常感谢,那写入文件呢?同样的方法可行吗? - Xtreme
我不确定你在问什么。为什么不试一下呢? - Wayne Werner
这种方法会破坏转义反斜杠(例如,用户输入字符“yes\no”)。Martijn的替代方法是在循环中调用输入更好。 - wim

6
请注意,如果要支持类似Python的字符串(不仅仅是\n,还有\t\r\u1234等),应使用带有unicode_escape处理程序的codecs.decode
contents = input()
contents = codecs.decode(contents, "unicode_escape")

请注意,这将会改变。
foo\nbar\\nbash\u1234

为了

foo
bar\nbashሴ

您还需要处理错误。您可以通过捕获UnicodeDecodeError或使用错误替换策略来实现:

contents = input()
contents = codecs.decode(contents, "unicode_escape", errors="replace")

不幸的是,这似乎会影响Unicode字符:

codecs.decode("α", "unicode_escape")
#>>> 'α'

我知道的最简单的修复方法是首先使用raw_unicode_escape进行转义:

contents = input()
contents = contents.encode("raw_unicode_escape")
contents = contents.decode("unicode_escape")

这可能比你需要的要复杂得多,所以我建议不要真的这样做。

"mess with" 实际上是一个 "α".encode('utf-8').decode('latin-1')。这并不是 unicode_escaperaw_unicode_escape 的合法用例(参见此处)。 - wim
使用 raw_unicode_escape 编码后跟 unicode_escape 解码的想法正在执行与原始问题无关的大量其他操作(并可能导致信息丢失)。例如,考虑将其与输入“s\t”和“s\t”一起使用,两者都将转换为输出中的 s + 制表符字符,而不是对于后者给出 s + 反斜杠 + t。对于在 input() 交互期间处理文字换行符,这才是真正问题的解决方法,Martijn 的答案似乎更好! - wim
@wim 我确实说过“如果你想支持Python风格的字符串”,在Python中,"s ""s\t"是相同的字符串。这是有意为之的。我同意,如果你*只关心换行符,那么这样做有点过头了。 - Veedrac
@wim 可能是因为我在测试包含反斜杠的字符串,所以使用了r-strings,但是是的,那个字符串不需要它。使用codecs是因为它允许你解码str,但对于最终的示例来说并不需要。我现在已经将其删除。 - Veedrac
答案现在更好了。我认为你没有抓住重点 - "s ""s\t"是相同的字符串,这一点没有争议,但"s\\t"是另一个不同的字符串!对于这个用例来说可能并不重要,因为似乎无法从input调用中获取"s\\t"的返回值。不管怎样,我仍然认为循环input比要求用户在数据中字面输入转义序列更好。 - wim
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接