仅打印字符串的某些行的最pythonic方式是什么?
What is the most pythonic way of printing only certain lines of a string?
假设我有一个跨越多行的字符串(不是文件):
multiline_string = '''I met a traveller from an antique land
Who said: Two vast and trunkless legs of stone
Stand in the desert... near them, on the sand,
Half sunk, a shattered visage lies, whose frown,
And wrinkled lip, and sneer of cold command,
Tell that its sculptor well those passions read
Which yet survive, stamped on these lifeless things,
The hand that mocked them and the heart that fed;
And on the pedestal these words appear:
'My name is Ozymandias, king of kings;
Look on my works, ye Mighty, and despair!'
Nothing beside remains. Round the decay
Of that colossal wreck, boundless and bare
The lone and level sands stretch far away.'''
我只想获取字符串的某些行,作为单个字符串(而不是字符串列表)。一种方法是这样的:
pedestal_lines = "\n".join(multiline_string.splitlines()[9:12])
print(pedestal_lines)
输出:
And on the pedestal these words appear:
'My name is Ozymandias, king of kings;
Look on my works, ye Mighty, and despair!'
但这种方式不是很好:它必须将字符串拆分为一个字符串列表,为这个列表建立索引,然后用 str.join()
方法将列表重新连接起来。更不用说,它看起来很丑,而且可读性不强。是否有更多 elegant/pythonic 方法来实现此目的?
如果您不想拆分字符串,您可以执行以下操作:
- 使用正则表达式捕获 8 行后的 3 行
- 计算换行符的位置并用正确的位置将字符串切片一次
你会原谅我在下面的代码中可能犯的一次性错误。
正则表达式:
import re
print(re.sub("^(.*\n){8}((?:.*\n){3})(.*\n){1,}",r"",multiline_string))
(创建一组8行,然后创建一组3行,然后其余的,替换为第二组)
位置提取+切片:
linefeed_pos = [i for i,c in enumerate(multiline_string) if c=="\n"]
print(multiline_string[linefeed_pos[7]:linefeed_pos[11]])
(在原始字符串上使用列表理解提取换行字符的位置,然后使用这些行索引位置进行切片)。这种方法的缺点是它会计算 所有 索引,而不仅仅是直到上界。这可以通过将生成器理解包装在列表理解中以在不再需要索引时停止来轻松解决:
linefeed_pos = [next (i for i,c in enumerate(multiline_string) if c=="\n") for _ in range(12)]
也许一个 slicing/extract 比拆分和合并更好的性能(我知道看到一个大列表浪费只是为了挑选 3 行是无法忍受的),但我不会称之为 pythonic。
如果 performance/memory 很重要,如果你有很多行,上面解释的两种方法都应该比你的方法更快。如果没有,则坚持您的解决方案。
假设我有一个跨越多行的字符串(不是文件):
multiline_string = '''I met a traveller from an antique land
Who said: Two vast and trunkless legs of stone
Stand in the desert... near them, on the sand,
Half sunk, a shattered visage lies, whose frown,
And wrinkled lip, and sneer of cold command,
Tell that its sculptor well those passions read
Which yet survive, stamped on these lifeless things,
The hand that mocked them and the heart that fed;
And on the pedestal these words appear:
'My name is Ozymandias, king of kings;
Look on my works, ye Mighty, and despair!'
Nothing beside remains. Round the decay
Of that colossal wreck, boundless and bare
The lone and level sands stretch far away.'''
我只想获取字符串的某些行,作为单个字符串(而不是字符串列表)。一种方法是这样的:
pedestal_lines = "\n".join(multiline_string.splitlines()[9:12])
print(pedestal_lines)
输出:
And on the pedestal these words appear:
'My name is Ozymandias, king of kings;
Look on my works, ye Mighty, and despair!'
但这种方式不是很好:它必须将字符串拆分为一个字符串列表,为这个列表建立索引,然后用 str.join()
方法将列表重新连接起来。更不用说,它看起来很丑,而且可读性不强。是否有更多 elegant/pythonic 方法来实现此目的?
如果您不想拆分字符串,您可以执行以下操作:
- 使用正则表达式捕获 8 行后的 3 行
- 计算换行符的位置并用正确的位置将字符串切片一次
你会原谅我在下面的代码中可能犯的一次性错误。
正则表达式:
import re
print(re.sub("^(.*\n){8}((?:.*\n){3})(.*\n){1,}",r"",multiline_string))
(创建一组8行,然后创建一组3行,然后其余的,替换为第二组)
位置提取+切片:
linefeed_pos = [i for i,c in enumerate(multiline_string) if c=="\n"]
print(multiline_string[linefeed_pos[7]:linefeed_pos[11]])
(在原始字符串上使用列表理解提取换行字符的位置,然后使用这些行索引位置进行切片)。这种方法的缺点是它会计算 所有 索引,而不仅仅是直到上界。这可以通过将生成器理解包装在列表理解中以在不再需要索引时停止来轻松解决:
linefeed_pos = [next (i for i,c in enumerate(multiline_string) if c=="\n") for _ in range(12)]
也许一个 slicing/extract 比拆分和合并更好的性能(我知道看到一个大列表浪费只是为了挑选 3 行是无法忍受的),但我不会称之为 pythonic。
如果 performance/memory 很重要,如果你有很多行,上面解释的两种方法都应该比你的方法更快。如果没有,则坚持您的解决方案。