Python 字母矩阵中高亮显示单词的完整实现教程

3次阅读

Python 字母矩阵中高亮显示单词的完整实现教程

本文详解如何在 python 生成的字母矩阵中精准高亮已找到的单词(如 word search),通过分离「坐标定位」与「样式渲染」逻辑,避免常见着色错误,确保每个匹配字符在原位置正确着色。

本文详解如何在 python 生成的字母矩阵中精准高亮已找到的单词(如 word search),通过分离「坐标定位」与「样式渲染」逻辑,避免常见着色错误,确保每个匹配字符在原位置正确着色。

在实现单词搜索(Word Search)类程序时,一个常见但易出错的需求是:在原始生成的矩阵中,仅将实际匹配到的单词字符高亮显示(如红色),其余字符保持原样。原始代码的问题在于:search_words() 函数试图在字符串拼接层面做条件着色(例如 if letter in word),这会导致语义错误——因为单个字母(如 ‘a’)可能属于多个单词,或与目标单词无关却因重合被误标;更严重的是,它未记录单词在矩阵中的真实行列坐标,导致无法在原矩阵上下文中精准着色。

正确的解法是遵循 “定位 → 标记 → 渲染” 三步分离原则

  1. 定位(Find):遍历矩阵各方向(水平、垂直、对角线等),对每个待搜索单词,返回其所有匹配起始坐标及方向长度;
  2. 标记(Mark):将所有匹配位置转换为 (row, col) 坐标列表,不修改原始数据;
  3. 渲染(Render):基于原始矩阵和坐标列表,生成带 ANSI 颜色的新矩阵,仅对指定位置应用 Fore.RED + char + Style.RESET_ALL。

以下为可直接运行的重构实现(兼容 VS Code 终端,需安装 colorama):

pip install colorama
from colorama import init, Fore, Style import random import math import json  init(autoreset=True)  # 自动重置样式,避免颜色污染后续输出  def generate_matrix(text):     # 提取纯字母并转小写     letters = [c.lower() for c in text if c.isalpha()]     n = len(letters)     if n == 0:         raise ValueError("输入文本不含有效字母")      size = math.ceil(math.sqrt(n))     total_cells = size * size     # 补齐空格使矩阵为正方形     padded = letters + [' '] * (total_cells - n)     random.shuffle(padded)     return [padded[i:i+size] for i in range(0, total_cells, size)]  # ✅ 步骤1:精准定位单词坐标(支持水平、垂直、主/反对角线) def find_word_coordinates(matrix, words):     coords = set()  # 使用 set 避免重复高亮同一位置     rows, cols = len(matrix), len(matrix[0])      # 水平搜索(左→右)     for i in range(rows):         row_str = ''.join(matrix[i])         for word in words:             start = 0             while True:                 pos = row_str.find(word, start)                 if pos == -1:                     break                 for k in range(len(word)):                     coords.add((i, pos + k))                 start = pos + 1      # 垂直搜索(上→下)     for j in range(cols):         col_str = ''.join(matrix[i][j] for i in range(rows))         for word in words:             start = 0             while True:                 pos = col_str.find(word, start)                 if pos == -1:                     break                 for k in range(len(word)):                     coords.add((pos + k, j))                 start = pos + 1      # 主对角线(↘,从左上到右下)     for i in range(rows):         for j in range(cols):             # 从 (i,j) 开始向右下延伸的最大长度             max_len = min(rows - i, cols - j)             diag_str = ''.join(matrix[i+k][j+k] for k in range(max_len))             for word in words:                 start = 0                 while True:                     pos = diag_str.find(word, start)                     if pos == -1:                         break                     for k in range(len(word)):                         coords.add((i + pos + k, j + pos + k))                     start = pos + 1      # 反对角线(↙,从右上到左下)     for i in range(rows):         for j in range(cols-1, -1, -1):             max_len = min(rows - i, j + 1)             diag_str = ''.join(matrix[i+k][j-k] for k in range(max_len))             for word in words:                 start = 0                 while True:                     pos = diag_str.find(word, start)                     if pos == -1:                         break                     for k in range(len(word)):                         coords.add((i + pos + k, j - pos - k))                     start = pos + 1      return list(coords)  # ✅ 步骤2:基于坐标渲染高亮矩阵 def highlight_matrix(matrix, coordinates):     highlighted = []     for i, row in enumerate(matrix):         new_row = []         for j, char in enumerate(row):             if (i, j) in coordinates:                 new_row.append(Fore.RED + char + Style.RESET_ALL)             else:                 new_row.append(char)         highlighted.append(new_row)     return highlighted  # ✅ 步骤3:统一搜索入口(返回高亮后矩阵) def search_and_highlight(matrix, words):     coords = find_word_coordinates(matrix, words)     return highlight_matrix(matrix, coords)  # —— 主程序逻辑 —— if __name__ == "__main__":     # 示例词典(实际使用时替换为你的 JSON 文件)     # with open('words_dictionary.json') as f:     #     words_to_search = [w for w in json.load(f) if len(w) >= 4]     words_to_search = ["cat", "dog", "rat", "art"]  # 简化测试用      text_input = input("Enter a text: ")      try:         matrix = generate_matrix(text_input)         print("nOriginal matrix:")         for row in matrix:             print(' '.join(row))          highlighted = search_and_highlight(matrix, words_to_search)         print("nMatrix with found words highlighted (red):")         for row in highlighted:             print(' '.join(row))      except ValueError as e:         print(f"Error: {e}")

关键注意事项与优化建议:

  • ✅ 坐标唯一性:使用 set() 存储坐标,自动去重。若同一位置被多个单词匹配(如 “art” 和 “rat” 共享 ‘r’),只高亮一次,避免样式嵌套冲突。
  • ✅ autoreset=True:colorama.init(autoreset=True) 是关键——它确保每个着色字符后自动重置样式,防止后续打印被意外染色(原始代码缺失此设置,常导致终端整行变红)。
  • ⚠️ 性能提示:对超大词典(如 37 万词),全量扫描会显著变慢。生产环境建议:
    • 限制搜索词长度(如 len(word) between 4 and 12);
    • 使用 Aho-Corasick 算法批量匹配(pyahocorasick 库);
    • 或预筛:仅搜索长度 ≤ 矩阵边长的单词。
  • ? 调试技巧:临时打印 find_word_coordinates(…) 返回的坐标列表,验证定位准确性(例如 print(“Found at:”, coords))。
  • ? 扩展样式:除 Fore.RED,还可组合 Style.BRIGHT 加粗,或用 Back.YELLOW 背景高亮:
    Fore.RED + Style.BRIGHT + char + Style.RESET_ALL

通过将「逻辑定位」与「视觉渲染」彻底解耦,代码不仅更健壮、易调试,也便于后续扩展(如添加反向搜索、模糊匹配或 GUI 可视化)。记住:永远先确定“哪里要改”,再决定“怎么改”——这是处理任何终端渲染问题的黄金法则。

立即学习Python免费学习笔记(深入)”;

text=ZqhQzanResources