Python汉字拆分程序:正方形分割友好输入方案技术问询
汉字偏旁分割程序:问题与解决方案
问题背景
我正在开发一款Python程序,用于将代表日文汉字的正方形分割为对应偏旁部首的带关联值小矩形,核心需求包括:
- 用户输入简洁代码后自动生成矩形坐标,在tkinter Canvas上显示并支持鼠标选择部首;
- 现有规则用
;处理上下分割、:+,处理左右分割,但无法适配大量汉字的特殊分割样式; - 希望通过递归算法生成坐标,但需保证输入友好;
- 需要支持矩形合并,处理L形、口形等非矩形部首;
- 考虑制作tkinter交互式输入组件替代纯代码输入。
当前数据用嵌套列表存储,例如示例0.5;0.5:0.15,0.35,0.5生成:
[[0.5,[[1,1]]],[0.5,[[0.15,1],[0.35,1],[0.5,1]]]] # 关联值标注见注释 ^ 关联值 ^ ^ ^
可行解决方案
一、优化分割代码规则+递归解析
现有规则的局限性在于仅支持单向层级分割,可通过括号嵌套扩展规则,实现任意复杂的分割组合,同时保留原有符号语义:
- 保留原定义:
;= 上下分割,:= 左右分割,分割比例用逗号分隔; - 用
()包裹子分割单元,支持递归嵌套。
扩展规则示例
- 上半部分左右分、下半部分上下分:
(0.6:0.4,0.6);(0.3;0.7) - 左侧上下分、右侧先左右分再上下分:
(0.4;0.6):(0.5:(0.2,0.8);0.5)
递归解析核心逻辑
def parse_code(code, parent_x0=0, parent_y0=0, parent_x1=1, parent_y1=1): # 处理括号嵌套的子分割 if '(' in code and ')' in code: start = code.index('(') end = code.index(')') inner_rects = parse_code(code[start+1:end], parent_x0, parent_y0, parent_x1, parent_y1) rest_code = code[:start] + code[end+1:] return inner_rects + (parse_code(rest_code, parent_x0, parent_y0, parent_x1, parent_y1) if rest_code else []) # 判断当前分割类型 split_char = None if ';' in code: split_char = ';' elif ':' in code: split_char = ':' if not split_char: # 基础单元,返回坐标与默认关联值 return [[parent_x0, parent_y0, parent_x1, parent_y1, 1]] # 按分割符号拆分比例并计算坐标 ratios = list(map(float, code.split(split_char))) total_ratio = sum(ratios) rects = [] current_pos = parent_y0 if split_char == ';' else parent_x0 for ratio in ratios: if split_char == ';': # 上下分割(y轴方向) y1 = current_pos + (parent_y1 - parent_y0) * (ratio / total_ratio) rects.append([parent_x0, current_pos, parent_x1, y1, 1]) current_pos = y1 else: # 左右分割(x轴方向) x1 = current_pos + (parent_x1 - parent_x0) * (ratio / total_ratio) rects.append([current_pos, parent_y0, x1, parent_y1, 1]) current_pos = x1 return rects
二、矩形合并功能实现
针对非矩形部首,通过交互式选择+包围盒合并处理:
- 在tkinter Canvas中,允许用户按住Shift选择多个相邻矩形;
- 合并逻辑:计算选中矩形的最小包围盒,替换原矩形并保留关联值;
- 可选添加撤销功能,记录合并前的状态。
合并核心代码
def merge_selected_rects(all_rects, selected_indices): selected_rects = [all_rects[i] for i in selected_indices] # 计算包围盒坐标 min_x = min(r[0] for r in selected_rects) min_y = min(r[1] for r in selected_rects) max_x = max(r[2] for r in selected_rects) max_y = max(r[3] for r in selected_rects) # 取第一个矩形的关联值,可改为自定义输入 merged_value = selected_rects[0][4] # 生成新的矩形列表 new_rects = [r for idx, r in enumerate(all_rects) if idx not in selected_indices] new_rects.append([min_x, min_y, max_x, max_y, merged_value]) return new_rects
三、tkinter交互式分割工具
替代纯代码输入,制作可视化交互组件:
- Canvas加载汉字背景图,作为分割参考;
- 工具栏提供按钮:「上下分割」「左右分割」「合并矩形」「导出代码」;
- 分割操作:点击分割按钮后拖动鼠标绘制分割线,自动计算比例并更新矩形列表;
- 实时预览分割效果,支持直接拖动矩形调整位置和大小。
分割交互核心代码
def start_vertical_split(event, canvas, rects): # 记录左右分割的起始x比例 start_x_ratio = event.x / canvas.winfo_width() def finish_split(e): end_x_ratio = e.x / canvas.winfo_width() # 生成分割代码并解析更新rects split_code = f"{abs(end_x_ratio - start_x_ratio)}:{1 - abs(end_x_ratio - start_x_ratio)}" new_rects = parse_code(split_code) # 更新Canvas显示(删除旧矩形,绘制新矩形) canvas.delete("rect") for r in new_rects: x0, y0, x1, y1, val = r canvas.create_rectangle(x0*canvas.winfo_width(), y0*canvas.winfo_height(), x1*canvas.winfo_width(), y1*canvas.winfo_height(), tags="rect", outline="black", fill="white") canvas.unbind('<ButtonRelease-1>') canvas.bind('<ButtonRelease-1>', finish_split)
内容的提问来源于stack exchange,提问作者Leo
相关产品推荐
相关产品推荐

