Cowsay 是那些你無法生活沒有的應用之一。
它基本上是根據傳遞給它的任何訊息生成ASCII圖片的一頭牛,以上的屏幕截圖中使用 fortune
生成。
不僅限於牛類,它還可以打印企鵝、麋鹿和許多其他動物。
聽起來像是一個適合移植到Go的有用應用!
我還喜歡它附帶的簡單英文許可證:
==============
cowsay 許可證
==============
cowsay 根據Perl的許可證進行分發:艺术许可证或GNU通用公共许可证。如果您不想為了自己去查找和閱讀這些許可證,請使用我更喜歡的部分:
(0)我是寫它的人,你不是。
(1)如果您將代碼用於其他目的,請給予應有的應有的好處。
(2)如果您有任何錯誤修復或建議,請通知我,以便我可以加以整合。
(3)如果您試圖從cowsay牟利,您就有問題。
讓我們從定義問題開始.我們想通過一個管道接受輸入,並讓我們的牛說出來.
第一個迭代從管道讀取用戶輸入並將其打印回來.沒有太複雜.
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main() {
info, _ := os.Stdin.Stat()
if info.Mode()&os.ModeCharDevice != 0 {
fmt.Println("該命令僅針對管道工作。")
fmt.Println("用法:fortune | gocowsay")
return
}
reader := bufio.NewReader(os.Stdin)
var output []rune
for {
input, _, err := reader.ReadRune()
if err != nil && err == io.EOF {
break
}
output = append(output, input)
}
for j := 0; j < len(output); j++ {
fmt.Printf("%c", output[j])
}
}
我們缺少了牛,而且還需要將消息包裝到一個漂亮格式的對話框內.
這是我們程序的第一次迭代:
package main
import (
"bufio"
"fmt"
"io"
"os"
"strings"
"unicode/utf8"
)
// buildBalloon 接收的参数是字符串切片和最大宽度maxwidth,
// 在第一行和最后一行首尾处添加边距,
// 然后在每行的开头和结尾处添加边距,并返回一个带有对话框内容的字符串
func buildBalloon(lines []string, maxwidth int) string {
var borders []string
count := len(lines)
var ret []string
borders = []string{"/", "\\", "\\", "/", "|", "<", ">"}
top := " " + strings.Repeat("_", maxwidth+2)
bottom := " " + strings.Repeat("-", maxwidth+2)
ret = append(ret, top)
if count == 1 {
s := fmt.Sprintf("%s %s %s", borders[5], lines[0], borders[6])
ret = append(ret, s)
} else {
s := fmt.Sprintf(`%s %s %s`, borders[0], lines[0], borders[1])
ret = append(ret, s)
i := 1
for ; i < count-1; i++ {
s = fmt.Sprintf(`%s %s %s`, borders[4], lines[i], borders[4])
ret = append(ret, s)
}
s = fmt.Sprintf(`%s %s %s`, borders[2], lines[i], borders[3])
ret = append(ret, s)
}
ret = append(ret, bottom)
return strings.Join(ret, "\n")
}
// tabsToSpaces 將`lines`切片中的所有制表符轉換為4個空格,以防止計算Rune時導致對齊錯誤
func tabsToSpaces(lines []string) []string {
var ret []string
for _, l := range lines {
l = strings.Replace(l, "\t", " ", -1)
ret = append(ret, l)
}
return ret
}
// calculateMaxWidth 接收一个字符串切片,返回长度最大的字符串长度
func calculateMaxWidth(lines []string) int {
w := 0
for _, l := range lines {
length := utf8.RuneCountInString(l)
if length > w {
w = length
}
}
return w
}
// normalizeStringsLength 接收一個字符串切片,並添加所需的空格數量,使它們的Rune數都相同
func normalizeStringsLength(lines []string, maxwidth int) []string {
var ret []string
for _, l := range lines {
s := l + strings.Repeat(" ", maxwidth-utf8.RuneCountInString(l))
ret = append(ret, s)
}
return ret
}
func main() {
info, _ := os.Stdin.Stat()
if info.Mode()&os.ModeCharDevice != 0 {
fmt.Println("該命令僅針對管道工作。")
fmt.Println("用法:fortune | gocowsay")
return
}
var lines []string
reader := bufio.NewReader(os.Stdin)
for {
line, _, err := reader.ReadLine()
if err != nil && err == io.EOF {
break
}
lines = append(lines, string(line))
}
var cow = ` \ ^_^
\ (oo)__\_
(\__)\ )\/\
||----w |
|| ||
`
lines = tabsToSpaces(lines)
maxwidth := calculateMaxWidth(lines)
messages := normalizeStringsLength(lines, maxwidth)
balloon := buildBalloon(messages, maxwidth)
fmt.Println(balloon)
fmt.Println(cow)
fmt.Println()
}
讓我們現在可配置化泡泡的圖形,通過添加一個 ‘劍龍’
把上面程序的中的 printFigure
的職能改成接收圖片的名字並打印出來。添加的支持是 ‘cow’ 和 ‘stegosaurus’.
// printFigure 给了一个圖片名字,會描繪出來。允許的值有 `cow` 和 `stegosaurus`.
func printFigure(name string) {
var cow = ` \ ^_^
\ (oo)__\_
(\__)\ )\/\
||----w |
|| ||
`
var stegosaurus = ` \ . .
\ / ` + "`" + `. .' "
\ .---. < > < > .---.
\ | \ \ - ~ ~ - / / |
\____ ..-~ ~-..-~
| | \~~~\\.' ` + "`" + `./~~~/
--------- \\_\_/ \\_\_/
.' O \ / / \ "
(\_____, ` + "`" + `.\_.' | } \/~~~/
` + "`" + `----. / } | / \\_\_/
` + "`" + `-. | / | / ` + "`" + `. ,~~|
~-.\____| /\_ - ~ ^| /- \_ ` + "`" + `..-'
| / | / ~-. ` + "`" + `-. \_ \_ \_
|\_____| |\_____| ~ - . \_ \_ \_ \_ \_>
`
switch name {
case "cow":
fmt.Println(cow)
case "stegosaurus":
fmt.Println(stegosaurus)
default:
fmt.Println("未知圖片")
}
}
func main() {
//...
var figure string
flag.StringVar(&figure, "f", "cow", "the figure name. Valid values are `cow` and `stegosaurus`")
flag.Parse()
//...
printFigure(figure)
fmt.Println()
}
我想我们已經達到了一個很好的地步。我只是希望能夠在系統中使用,而不是運行 go run main.go
,所以我只需要輸入 go build
和 go install
。
現在我可以花整天時間與 gololcat 和 gocowsay 來享受了。