首页 > 试题广场 >

聊天消息排版

[编程题]聊天消息排版
  • 热度指数:295 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解

在网游中,聊天功能是一项非常重要的功能,加上玩家可以打出游戏内置的一些表情图片,因此需要实现一个图文混排系统,如上图所示。

玩家在聊天框输入的是一段utf-8编码的文字,且只会包含中文、英文、中英文的标点符号和空格(不会出现换行、回车和制表符)。按照网易游戏的传统,井号(#)是作为一个转义字符,支持下面几种转义行为:

1. #加一个数字来表示内置的表情图片,为了简化问题,我们这里只支持20个表情图片,从0开始计数,并且数字是按最长匹配原则去匹配,比如 #0 表示0号表情图片、#1 表示1号表情图片 、#19表示19号表情图片、#20则表示2号表情图片后面加数字0。需要注意的是#00表示的是0号表情图片加后面数字0

2. #r 表示换行,遇到以后会自动切换到下一行开始排版。

3. ## 表示显示出#这个符号

4.如果玩家不按规则输入错误的转义,则按照玩家的输入原样显示,比如#a##,#

 


上图所示的玩家输入为:Hello world#大家好#r欢迎大家参加网易雷火校园招聘#1祝大家取得好成绩”

 

排版的时候需要像上图一样,将文字从起始位置开始,依次显示在聊天窗口里,一些显示规则如下所示:

1.聊天窗口的宽度固定为W像素,起始坐标为左上角,坐标为(0, 0),右上角坐标为(W-1, 0),坐标向右向下增长。任何文字和表情必须显示在窗口内,不能超出窗口。但是高度可以无限向下延伸。

2.显示的字体均为等宽字体,英文(包括英文标点符号和空格)的字体宽度统一为XE,高度统一为YE。中文(包括中文的标点符号)的字体宽度统一为XC,高度统一为YC

3.每个表情图片的宽高是独立的,0号表情图片的宽度为 X0,高度Y0,依次类推,19号表情图片的宽度为X19,高度为Y19

4.字符(中英文以及标点符号、空格等,下同)与字符之间、字符与表情之间、表情与表情之间都需要额外保留一个PX像素的字间距。每一行第一个字符左边,以及最后一个字符右边不需要保留字间距。

5.当下一个字符或者表情无法在本行W宽度的像素内完整显示的话,则会强行换到下一行首开始显示。遇到#r的时候也会自动换到下一行开始显示下一个字符或表情。

6.在一行里出现高度不同的中英文以及表情的时候,需要将其底部对齐。

7.当一行里没有任何字符或表情,直接被#r换行的时候,这一行的高度算英文字体的高度。

8.每一行里高度最高的字符或表情,需要同上一行的的底部保留PY像素的行间距。第一行上面与最后一行下面不需要保留行间距。

9.最后一个字符或表情显示显示以后,它的右下角坐标则为结束坐标。也就是本题需要求解的问题。输入保证最后不会以#r结尾。


输入描述:
每个测试输入包含1个测试用例

第一行为7个正整数W, XE, YE, XC, YC, PX, PY

第二行为40个正整数X0,
Y0, X1, Y1…X19, Y19

第三行为长度不超过10000的十六进制编码过的玩家输入,即玩家输入的utf-8编码的数据每个字节的数字转成大写的十六进制表示,不足两位的话前面补0(同C里printf的%X格式化),然后不同字节的十六进制编码表示依次拼接起来。

比如Hello的十六进制编码表示为48656C6C6F。

前两行的各个数字含义如上文描述,其中50<W<10000,0<其他<50。


输出描述:
输出用空格隔开的两个数字,表示结束坐标
示例1

输入

60 2 4 3 4 1 3
7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6 7 6
48656C6C6F20776F726C6423E5A4A7E5AEB6E5A5BD2372E6ACA2E8BF8EE5A4A7E5AEB6E58F82E58AA0E7BD91E69893E99BB7E781ABE6A0A1E59BADE68B9BE881982331E7A59DE5A4A7E5AEB6E58F96E5BE97E5A5BDE68890E7BBA9

输出

38 19
# 在上面老哥的基础上稍加修改了一下
# 添加了中文注释并重新梳理了一下代码逻辑,简化了部分计算
import sys

lines = []

try:
    while True:  # 获取所有输入
        line = sys.stdin.readline().strip()
        if line == '':
            break
        lines.append(line.split())
except:
    pass
w, xe, ye, xc, yc, px, py = map(int, lines[0])
img_size = list(map(int, lines[1]))
# 将UTF-8编码表示解码为字符串。
string = lines[2][0]
bt = bytes.fromhex(string.lower())
string = bytes.decode(bt)

index = 0
pos = [-px, 0]  # 初始化坐标
height = 0  # 初始化行高
while (index < len(string)):
    char = string[index]  # 当前字符
    block_size = (xe, ye)  # 默认为英文字符
    index += 1
    # 非英文字符(0xf4之前全部都是英文字符、英文标点与空格)
    if ord(char) >= 0xf4:
        block_size = (xc, yc)  # 中文block大小
    # 如果是英文字符中的#字符,且依然有下一位字符,考虑转译
    elif char == '#' and index < len(string):
        char = string[index]
        index += 1
        # 转译为换行符
        if char == 'r':
            if height==0:
                height=ye
            pos = [-px, pos[1] + py + height]
            height = 0
            continue
        # 转译为图片
        elif '0' <= char <= '9':
            # “#”字符后为“1”且再后面存在字符且字符在“0”到“9”之间
            if char == '1' and index < len(string) and '0' <= string[index] <= '9':
                index += 1
                img_num = int(string[index - 2:index])  # 取对应img的编号
            else:
                img_num = int(char)  # 取对应img的编号
            block_size = img_size[img_num * 2:img_num * 2 + 2]  # block大小为对应img的大小
        # 如果不符合转译规则,正常输出
        elif char != '#':
            index -= 1
    # 其他情况均为英文字符,使用默认block

    # 根据已经判定好的block,判断行高height与坐标pos的变化
    # 如果X累计超过上限W,另起一行,Y加上行距和行高。
    X = pos[0] + px + block_size[0]
    if X > w:
        X, Y = block_size[0], pos[1] + py + height
        pos = [X, Y]
        height = block_size[1]
    else:
        # 如果不换行,判断行高height是否更新,X加上行距和block的长
        height = max(block_size[1], height)
        pos[0] += px + block_size[0]

# 最终输出要求的是最后一行的右下角(最后一个block右下角)
# 而pos是最后一行的右上角(因为还没有加行高)
print(pos[0] - 1, pos[1] + height - 1)

编辑于 2023-04-20 19:49:43 回复(0)
怎么有还要求转utf-8的,细节太多,调试令人头大。
w, xe, ye, xc, yc, px, py = map(int, input().split())
img_size = list(map(int, input().split()))

string = input()
bt = bytes([int(string[i*2:i*2+2],16) for i in range(len(string)//2)])
string = bt.decode('utf-8')

index = 0
pos = [-px, 0]
height = 0
while(index < len(string)):
    char = string[index]
    block_size = (xe, ye)  # default
    index += 1
    # chinese
    if ord(char) > 255:
        block_size = (xc, yc)
    # #
    elif char == '#' and index < len(string):
        char = string[index]
        index += 1
        # new line
        if char == 'r':
            if pos[0] == -px:
                pos[1] += ye
            pos = [-px, pos[1]+py]
            height = 0
            continue
        # img
        elif '0' <= char <= '9':
            if char == '1' and index < len(string) and '0' <= string[index] <= '9':
                index += 1
                img_num = int(string[index-2:index])
            else:
                img_num = int(char)
            block_size = img_size[img_num*2:img_num*2+2]
        # mismatch
        elif char != '#':
            index -= 1
    
    if pos[0]+px+block_size[0] > w:
        pos = [block_size[0], pos[1]+py+block_size[1]]
        height = block_size[1]
    else:
        if block_size[1] > height:
            pos[1] = pos[1]+block_size[1]-height
            height = block_size[1]
        pos[0] += px+block_size[0]
        
print(pos[0]-1, pos[1]-1)


发表于 2020-08-16 09:23:56 回复(0)