@Mufeed 的回答非常好,非常适合初学者。这个答案有点复杂。
我建议的一件事是使用 Python 的多行字符串来编写您的信件。它使它们更容易编辑。我的字母有点大,我只定义了三个字母 b、g 和 i(在 emacs 中使用艺术家模式..):
letter_definitions = {
'b': Letter("""
****************
******************
***** *****
*** ***
*** ****
*** ****
*** ******
******************
*********************
*** * *****
*** ******
*** *****
*** ****
*** ****
*** ****
*** ****
*** **********
*********************
*****************
"""),
'g': Letter("""
****************
*** * **** **
*** *****
****
****
*****
****
****
**** ************
**** *************
***** *
***** *
***** **
****** *
******* **
********* *****
*************
"""),
'i': Letter("""
+---+
|***|
+---+
+-+
|*|
|*|
|*|
|*|
|*|
|*|
+-+
"""),
}
Letter 类存储形状,记录高度/宽度/基线(__init__ 方法),并且可以将自身写入二维缓冲区(add_to_buffer() 方法):
import textwrap
class Letter(object):
def __init__(self, shape):
# remove space to the left (textwrap.dedent)
# and split the shape string into lines (self.shape is a list of strings)
self.shape = textwrap.dedent(shape).split('\n')
# remove any initial empty lines
while self.shape[0] == '':
self.shape = self.shape[1:]
# remove any trailing empty lines
while self.shape[-1] == '':
self.shape = self.shape[:-1]
self.height = len(self.shape)
self.width = max(len(line) for line in self.shape)
# we're doing the easy case where all letters are capitals
# and the baseline is at the bottom
self.baseline = self.height
def add_to_buffer(self, buffer, x, y):
"Write this letter shape to a 2-dimensional buffer at position x, y."
# justify our baseline with the buffer's baseline
y += buffer.baseline - self.baseline
# keeping track of which line and character we're at,
# we go through each line in the shape
for lineno, line in enumerate(self.shape):
# .. and each character in the line
for charpos, ch in enumerate(line):
# and put the character into the buffer
buffer[x + charpos, y + lineno] = ch
缓冲区在TextLine 类中实现,它通过询问每个字母的高/宽来创建足够大小的(模拟的)二维缓冲区来容纳所有字母形状:
class TextLine(object):
def __init__(self, letters):
self.letters = letters
self.width = sum(letter.width for letter in self.letters)
# one space between each letter, except the last one
self.width += len(self.letters) - 1
self.height = max(letter.height for letter in self.letters)
self.baseline = self.height
# add letters to buffer
self.buffer = [' '] * (self.width * self.height) # should probably use a buffer.buffer here..
x = 0
for letter in self.letters:
letter.add_to_buffer(self, x, 0)
x += letter.width + 1
def __setitem__(self, (x, y), ch):
# calculate the position and assign the character
self.buffer[y * self.width + x] = ch
def __str__(self):
chunks = []
# divide the buffer into pieces/chunks of length self.width..
# (see https://*.com/a/312464/75103 for how this works)
for i in range(0, len(self.buffer), self.width):
chunk = self.buffer[i:i + self.width]
chunks.append(''.join(chunk))
# .. and start each chunk on a new line
return '\n'.join(chunks)
最后我将 print_big() 函数重命名为 big_text() 并返回要打印的字符串:
def big_text(text):
lines = text.splitlines(False) # don't keep newlines
res = []
for line in lines:
# convert each character to the corresponding Letter
letters = [letter_definitions[ch] for ch in line]
# put the letters into a TextLine
text_line = TextLine(letters)
# and append the buffer to the result
res.append(str(text_line))
return '\n\n'.join(res)
很多时候你需要重用这些函数,如果它们返回字符串而不是打印它,那么重用它们会更容易,而且你可以像打印一样简单地使用它:
print big_text('big')
结果:
****************
******************
***** ***** ****************
*** *** *** * **** **
*** **** *** *****
*** **** ****
*** ****** ****
****************** +---+ *****
********************* |***| ****
*** * ***** +---+ ****
*** ****** **** ************
*** ***** +-+ **** *************
*** **** |*| ***** *
*** **** |*| ***** *
*** **** |*| ***** **
*** **** |*| ****** *
*** ********** |*| ******* **
********************* |*| ********* *****
***************** +-+ *************