Rust 实现新世纪五笔反查词库

背景

新世纪版五笔字型输入法,简称新世纪五笔,是王永民教授于2008年1月28日推出的第三代五笔字型输入法(第一代的86五笔和第二代的98五笔分别于1983年和1998年推出),该版本也被称为标准版王码五笔。新世纪五笔建立在新的字根键位体系,重码实用频度降低,取码更加规范,打字更加顺手,在规律性、易学性等方面有显著的进步。

优点非常多但目前很多输入法软件默认还不支持新世纪五笔,特别是mac系统上的支持更慢一些。我目前主要使用清歌输入法,这个默认可以切换86和98的词库,也支持自定义词库。网络上找到的大部分新世纪词库只有主词库,没有反查功能,新世纪中为了输入的方便性很多字的拆分方式和按键都有变化不能反查真的很不方便。

鉴于此种尴尬情况,我们是否可以自己生成反查词库呢?当然是可以地!

ciku.jpg

思路

首先可以查看系统自带的主词库是这样的:

a 工
aaaa 工 恭恭敬敬
aaad 工期
aaae 黄花菜
aabg 草草了事
aahg 工卡
aahh 工频 茞 茝
aaif 葡萄汁
aaii 落花流水
aaip 工党
aais 葡萄酒 戒酒

一行一条数据前面是输入码后面是可以输入的文字 空格分割。

然后可以查看系统自带的反查词库如下:

㣻   rnu
㣼   nvyy
㣽   vnu
㣾   ncyy
㤈   nny
㤉   naht
㤊   nrry
㤋   nwvt
㤌   nfg

也是一行一条数据,但前面是文字结果后面对应的码。

那根据主词库生成反查词库是不是很清晰了:

  • 读取主词库内容
  • 根据换行符和空格符分割数据为数组
  • 遍历数组生成一个文字对应一个码
  • 结果写入文本文件生成反查词库

功能实现

use std::fs::File;
use std::io::prelude::*;

// 源文件绝对路径
const SOURCE_FILE: &'static str = "/Users/aqrun/xxx/新世纪五笔词库.txt";
// 目标文件绝对路径
const DIST_FILE: &'static str = "/Users/aqrun/xxx/新世纪五笔反查词库.txt";
// 测试用开关控制待处理数据量
const TOTAL: i32 = 100;
// 是否开启控制开关
const LIMIT: bool = false;

fn main() {
    // 获取源文件句柄 file
    let mut file = File::open(SOURCE_FILE).expect("源文件打开失败,请检查文件路径");
    let mut source_data = String::new();
    // 读取源文字内容到 source_data
    file.read_to_string(&mut source_data).expect("源文件内容读取失败");

    // 生成结构化数据
    let res = generate_data(&source_data);
    // 根据结构化数据转为最终文件内容
    let dist_data = generate_file_content(&res);

    // 获取目标文件句柄
    let mut dist_file = File::create(DIST_FILE).expect("目标文件创建失败,请检查路径");
    // 写入内容
    dist_file.write_all(&dist_data.as_bytes()).expect("文件写入失败");
    // println!("{:?}", dist_data);
    println!("转换完成! 共处理{}条数据!", res.len());
}

/**
 * 将源数据字符串转换为结构化的数组数据
 */
fn generate_data(source: &str) -> Vec<Vec<String>> {
    // println!("{:?}", source);
    // 保存所有数据 按行分割原始内容为数组
    let line_data_arr: Vec<&str> = source.split('\n').collect();
    // 保存最后的结果
    let mut res: Vec<Vec<String>> = Vec::new();

    let mut index = 0;
    for i in line_data_arr.iter() {
        index += 1;
        // 测试用控制开关
        if LIMIT && index > TOTAL {
            break;
        }

        if i.is_empty() {
            continue;
        }
        // 按空格分割当前行字符串为数组
        let all_arr: Vec<&str> = i.split(" ").collect();
        // 当前行数据大小
        let len = all_arr.len();
        // 当前行字符编码
        let code = all_arr[0];
        
        for j in 1..len {
            // println!("{:?}, {}, {}, {}", all_arr, len, j, len-2);
            // 将当前行生成为 [编码, 文字] 数组格式 一行一个文字
            let mut res_line: Vec<String> = Vec::new();
            res_line.push(all_arr[j].to_string());
            res_line.push(code.to_string());
            res.push(res_line);
        }
    }
    
    res
}

/**
 * 将结构化数据转为最终文件内容
 */
fn generate_file_content(source_arr: &Vec<Vec<String>>) -> String {
    let mut dist_arr: Vec<String> = Vec::new();
    // println!("res: {:?}", res);

    for i in source_arr {
        dist_arr.push(i.join(" ").to_string());
    }

    dist_arr.join("\n")
}

运行程序

ζ cargo run --bin main                                                                                                             
   Compiling myrust v0.1.0 (/workspace/myrust)
    Finished dev [unoptimized + debuginfo] target(s) in 0.70s
     Running `target/debug/main`
转换完成! 共处理89794条数据!

着不多9W条数据大概用了0.7秒,还是很快的吧应该。

最终生成文件内容类似:

工 a
恭恭敬敬 aaaa
工期 aaad
黄花菜 aaae
工巧 aaag
葡萄牙 aaah
花花世界 aaal
工艺 aaan
工匠 aaar
工区 aaar
工薪 aaau
菚 aaau
斯蒂芬 aaaw

完结!!!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 目录 1. 输入方案介绍1.1. 新世纪五笔1.2. 新世纪五笔·拼音1.3. 新世纪五笔·简入繁出 2. 依赖 ...
    科研者阅读 13,457评论 1 5
  • 一、概述 声笔飞码,简称飞码,是在输入法界影响最大的顶功输入法,可以说是它直接或者间接地激发了其它非声笔系列顶功输...
    声笔系列阅读 7,821评论 0 0
  • 前提:安装 fcitx RIME安装:$ sudo pacman -S fcitx-rime 注销生效 一些快捷键...
    titvax阅读 4,705评论 0 0
  • 一、概述 声笔快码,简称快码,是一款类双拼输入法,它采用了一种特殊的双拼加笔画编码,同时又融合的 105 个高频声...
    声笔系列阅读 4,688评论 0 0
  • 虽然见解略有不同,但与 @晓览 的基本观点相同,新世纪五笔是一种比老86、98版都要更差的五笔版本。 与 @晓览 ...
    Ubuntu_2017阅读 13,616评论 7 7