/*
读取酒水订单文件,让酒水分类显示。
并且订单边缘对齐,酒水名首字母大写
酒水订单文件:
shandy,Dragon's Breath,5.91
elixir,shirley's temple,4.12
meal,goblet of la croix,1.22
desert dessert,pickled camel hump,7.33
elixir,iced boilermaker,11.22
完成后的输出应该像这样:
*** Welcome to Taernyl's Folly ***
~[shandy]~
Dragon's Breath...............5.91
~[elixir]~
Iced Boilermaker.............11.22
Shirley's Temple..............4.12
~[meal]~
Goblet of La Croix............1.22
~[desert dessert]~
Pickled Camel Hump............7.33
*/
import java.io.File
import java.util.*
//酒馆名称
const val TAVERN_NAME = "Taernyl's Folly"
//读取菜单文件
val menuList = File("data/tavern-menu-items")
.readText() //返回 String 类型数据
.split("\r\n") //注意此处需要用\r\n
fun main() {
println("*** Welcome to $TAVERN_NAME ***")
val menu = formatMenu(menuList)
menu.forEach { line ->
println(line)
}
}
//不用首字母大写的单词
var lowercaseWords = setOf("a", "of", "or", "and")
//返回格式化后的菜单
fun formatMenu(menuData: List<String>): List<String> {
val subList = mutableListOf<String>()
var width = 0
for (line in menuData) {
val (kind, drink, price) = line.split(',')
val length = drink.length + price.length
if (length > width) {
width = length
}
//直接在这里查询是否有同种类的订单,归类整理,以及将酒水字母大写
val i = subList.indexOf(kind)
if (i == -1) {
subList.add(kind)
subList.add(capitalString(drink, lowercaseWords))
subList.add(price)
} else {
//每次始终在找到的数据后插入(从后向前倒着插:none、价格、酒水名)
//插入完顺序为:(原种类名)、酒水名、价格、none
//此处插入一个 none 标志占位,以便将来以 3 为间隔对每个种类和订单做不同处理
subList.add(i + 1, "none")
subList.add(i + 1, price)
subList.add(i + 1, capitalString(drink, lowercaseWords))
}
}
//获得首行长度
val standardWidth = "*** Welcome to $TAVERN_NAME ***".length
//若订单长度比首行至少短5个字符,填充点与首行边缘对齐;否则直接在两项之间填充5个点
width = if (width + 5 <= standardWidth) standardWidth else (width + 5)
//遍历子项列表,生成新菜单
val menuList = mutableListOf<String>()
val size = subList.size
for (i in 0 until size step 3) {
if (subList[i] != "none") {
val kindLine = getKind(width, subList[i])
menuList.add(kindLine)
}
var menuLine = subList[i + 1]
menuLine += getDot(width, subList[i + 1], subList[i + 2])
menuLine += subList[i + 2]
menuList.add(menuLine)
}
return menuList
}
//返回适当数量的点字符串
fun getDot(width: Int, drink: String, price: String): String {
var dot = ""
while (drink.length + price.length + dot.length < width) {
dot += '.'
}
return dot
}
//将字串中的各个单词首字母大写
//参数:字串,无需大写的字串集合
fun capitalString(str: String, lowercaseWords: Set<String>): String {
var newStr = ""
val list = str.split(' ')
list.forEach { s ->
//如果是不必大写的单词则不写
newStr += if (lowercaseWords.contains(s)) s else s.replaceFirstChar {
if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()
}
newStr += ' '
}
//去除末尾空格
newStr.take(newStr.length - 1)
return newStr
}
//返回居中的酒水分类字符串
fun getKind(width: Int, kind: String): String {
var line = "~[$kind]~"
var spaceCount = (width - line.length) / 2
//在字符串前后添加空格
while (line.length < width) {
line = ' ' + line
if(line.length >= width) break
line += ' '
}
return line
}
运行效果