2021/06/28

HanLP

Han Language Processing 是 NLP Toolkit,1.x 版以 java 開發,目前正在做 2.x 版,改以 python 開發。1.x 版如果要用 python 呼叫,要用 pyhanlp 套件,內部也是透過 jpype 套件呼叫 java 的程式介面,但因為 JVM 的限制,無法在程式中 shutdown 並 restart JVM。

HanLP 1x 的文件有將所有功能列出來

設定

先建立一個 Maven Project,在 pom.xml 中加入

<dependency>
    <groupId>com.hankcs</groupId>
    <artifactId>hanlp</artifactId>
    <version>portable-1.7.8</version>
</dependency>

下載 data.zip,解壓縮後得到 dictionary 與 model 兩個目錄,放到 project 的 data 目錄中。

下載 hanlp-release.zip ,解壓縮後,只要取 hanlp.properties,把檔案放到 project 的 classpath 中,如果 data 目錄為 /project/hanlp/data,修改第一行為

root=/project/hanlp/

Demo

import com.hankcs.hanlp.HanLP;

public class Test {
    public static void main(String[] args) {
        System.out.println(HanLP.segment("你好,欢迎使用HanLP汉语处理包!"));
    }
}

執行結果為分詞以及詞性

[你好/l, ,/w, 欢迎/v, 使用/v, HanLP/nx, 汉语/nz, 处理/v, 包/v, !/w]

如果將同樣的句子改為繁體中文,其分詞的結果不如預期那麼好,甚至把 歡 漢 判斷為標點符號

[你好/l, ,/w, 歡/w, 迎/v, 使用/v, HanLP/nx, 漢/w, 語處/n, 理/n, 包/v, !/w]

標準分詞

List<Term> termList = StandardTokenizer.segment("商品和服务");
System.out.println(termList);

HanLP.segment 就是封裝了 StandardTokenizer.segment

NLP 分詞

System.out.println(NLPTokenizer.segment("我新造一个词叫幻想乡你能识别并标注正确词性吗?"));
// 注意观察下面两个“希望”的词性、两个“晚霞”的词性
System.out.println(NLPTokenizer.analyze("我的希望是希望张晚霞的背影被晚霞映红").translateLabels());
System.out.println(NLPTokenizer.analyze("支援臺灣正體香港繁體:微软公司於1975年由比爾·蓋茲和保羅·艾倫創立。"));

執行結果

[我/r, 新/d, 造/v, 一个/m, 词/n, 叫/v, 幻想乡/ns, 你/r, 能/v, 识别/v, 并/c, 标注/v, 正确/a, 词性/n, 吗/y, ?/w]
我/代词 的/助词 希望/名动词 是/动词 希望/动词 张/量词 晚霞/名词 的/助词 背影/名词 被/介词 晚霞/名词 映红/动词
支援/v 臺灣/ns 正體/n 香港/ns 繁體/n :/w 微软公司/ntc 於/p 1975年/t 由/p 比爾·蓋茲/nr 和/c 保羅·艾倫/nr 創立/v 。/w

剛剛 Demo 繁體中文發生的問題,改用 NLPTokenizer.analyze 可以解決

System.out.println(NLPTokenizer.analyze("你好,歡迎使用HanLP漢語處理包!"));

執行結果

你好/l ,/w 歡迎/v 使用/v HanLP/nx 漢語/nz 處理/vn 包/n !/w

索引分詞

索引分詞 IndexTokenizer 是用在搜索引擎的分詞器,另外可用 term.offset 取得單詞偏移量

List<Term> termList = IndexTokenizer.segment("主副食品");
for (Term term : termList)
{
    System.out.println(term + " [" + term.offset + ":" + (term.offset + term.word.length()) + "]");
}

執行結果

主副食品/n [0:4]
主副食/j [0:3]
副食品/n [1:4]
副食/n [1:3]
食品/n [2:4]

N-最短路徑分詞

        Segment nShortSegment = new NShortSegment().enableCustomDictionary(false).enablePlaceRecognize(true).enableOrganizationRecognize(true);
        Segment shortestSegment = new DijkstraSegment().enableCustomDictionary(false).enablePlaceRecognize(true).enableOrganizationRecognize(true);
        String[] testCase = new String[]{
                "提供第一手全球各地最即时的突发事件报导,为网友精准掌握新闻脉动",
                "指挥中心再次呼吁民众进入医疗机构务必全程佩戴口罩",
        };
        for (String sentence : testCase)
        {
            System.out.println("N-最短分词:" + nShortSegment.seg(sentence) + "\n最短路分词:" + shortestSegment.seg(sentence));
        }

執行結果

N-最短分词:[提供/v, 第一/m, 手/n, 全球/n, 各地/r, 最/d, 即时/d, 的/uj, 突发/vn, 事件/n, 报导/n, ,/w, 为/p, 网友/n, 精/a, 准/a, 掌握/v, 新闻/n, 脉/ng, 动/v]
最短路分词:[提供/v, 第一/mq, 手/n, 全球/n, 各地/r, 最/d, 即时/d, 的/uj, 突发/vn, 事件/n, 报导/n, ,/w, 为/p, 网友/n, 精/a, 准/a, 掌握/v, 新闻/n, 脉/ng, 动/v]

N-最短分词:[指挥中心/nt, 再次/d, 呼吁/v, 民众/n, 进入/v, 医疗机构/nt, 务必/d, 全程/n, 佩戴/v, 口罩/n]
最短路分词:[指挥中心/nt, 再次/d, 呼吁/v, 民众/n, 进入/v, 医疗机构/nt, 务必/d, 全程/n, 佩戴/v, 口罩/n]

CRF 分詞

CRF 對於新的詞的辨識比較好

CRFLexicalAnalyzer analyzer = new CRFLexicalAnalyzer();
String[] tests = new String[]{
  "商品和服务",
  "指挥中心再次呼吁民众进入医疗机构务必全程佩戴口罩",
  "微软公司於1975年由比爾·蓋茲和保羅·艾倫創立,18年啟動以智慧雲端、前端為導向的大改組。" // 支持繁体中文
};
for (String sentence : tests) {
  System.out.println(analyzer.analyze(sentence));
}

執行結果

商品/n 和/c 服务/vn
指挥/vn 中心/n 再次/d 呼吁/v 民众/n 进入/v 医疗机构/nz 务必/d 全程/n 佩戴/v 口罩/n
微软公司/ntc 於/p 1975年/t 由/p 比爾·蓋茲/n 和/c 保羅·艾倫/v 創立/v ,/w 18年/t 啟動/v 以/p 智慧/n 雲端/n 、/w 前端/n 為/v 導向/n 的/u 大/a 改組/vn 。/w

極速詞典分詞

以 AhoCorasickDoubleArrayTrie 實作的詞典分詞

String text = "江西鄱阳湖干枯,中国最大淡水湖变成大草原";
        System.out.println(SpeedTokenizer.segment(text));
        long start = System.currentTimeMillis();
        int pressure = 1000000;
        for (int i = 0; i < pressure; ++i)
        {
            SpeedTokenizer.segment(text);
        }
        double costTime = (System.currentTimeMillis() - start) / (double)1000;
        System.out.printf("分词速度:%.2f字每秒", text.length() * pressure / costTime);

執行結果

[江西/null, 鄱阳湖/null, 干枯/null, ,/null, 中国/null, 最/null, 大/null, 淡水湖/null, 变成/null, 大/null, 草原/null]
分词速度:14792899.41字每秒

自訂詞典

// 动态增加
        CustomDictionary.add("攻城狮");
        // 强行插入
        CustomDictionary.insert("白富美", "nz 1024");
        // 删除词语(注释掉试试)
//        CustomDictionary.remove("攻城狮");
        System.out.println(CustomDictionary.add("单身狗", "nz 1024 n 1"));
        System.out.println(CustomDictionary.get("单身狗"));

        String text = "攻城狮逆袭单身狗,迎娶白富美,走上人生巅峰";  // 怎么可能噗哈哈!

        // AhoCorasickDoubleArrayTrie自动机扫描文本中出现的自定义词语
        final char[] charArray = text.toCharArray();
        CustomDictionary.parseText(charArray, new AhoCorasickDoubleArrayTrie.IHit<CoreDictionary.Attribute>()
        {
            public void hit(int begin, int end, CoreDictionary.Attribute value)
            {
                System.out.printf("[%d:%d]=%s %s\n", begin, end, new String(charArray, begin, end - begin), value);
            }
        });

        // 自定义词典在所有分词器中都有效
        System.out.println(HanLP.segment(text));
true
nz 1024 n 1 
[0:3]=攻城狮 nz 1 
[5:8]=单身狗 nz 1024 n 1 
[11:14]=白富美 nz 1024 
[攻城狮/nz, 逆/vg, 袭/v, 单身狗/nz, ,/w, 迎娶/v, 白富美/nz, ,/w, 走/v, 上/f, 人生/n, 巅峰/n]

CustomDictionary 是 global 自定詞典,可以隨時增刪

自訂詞典並不代表就一定能取得該分詞的結果,例如 "川普" 跟 "四川普通人" 的問題

com.hankcs.hanlp.seg.Segment#enableCustomDictionaryForcing 可使用這個

人名辨識

所有的分詞器預設都開啟了人名識別

String[] testCase = new String[]{
        "签约仪式前,秦光荣、李纪恒、仇和等一同会见了参加签约的企业家。",
        "王国强、高峰、汪洋、张朝阳光着头、韩寒、小四",
        "张浩和胡健康复员回家了",
        "王总和小丽结婚了",
        "编剧邵钧林和稽道青说",
        "这里有关天培的有关事迹",
        "龚学平等领导,邓颖超生前",
        };
Segment segment = HanLP.newSegment().enableNameRecognize(true);
for (String sentence : testCase)
{
    List<Term> termList = segment.seg(sentence);
    System.out.println(termList);
}

執行結果

[签约/v, 仪式/n, 前/f, ,/w, 秦光荣/nr, 、/w, 李纪恒/nr, 、/w, 仇和/nr, 等/u, 一同/d, 会见/v, 了/ul, 参加/v, 签约/v, 的/uj, 企业家/n, 。/w]
[王国强/nr, 、/w, 高峰/n, 、/w, 汪洋/n, 、/w, 张朝阳/nr, 光着头/l, 、/w, 韩寒/nr, 、/w, 小四/nr]
[张浩和/nr, 胡健康/nr, 复员/vn, 回家/v, 了/ul]
[王总/nr, 和/c, 小丽/nr, 结婚/v, 了/ul]
[编剧/n, 邵钧林/nr, 和/c, 稽道青/nr, 说/v]
[这里/r, 有/v, 关天培/nr, 的/uj, 有关/vn, 事迹/n]
[龚学平/nr, 等/u, 领导/n, ,/w, 邓颖超/nr, 生前/t]

音譯人名識別

String[] testCase = new String[]{
                "一桶冰水当头倒下,微软的比尔盖茨、Facebook的扎克伯格跟桑德博格、亚马逊的贝索斯、苹果的库克全都不惜湿身入镜,这些硅谷的科技人,飞蛾扑火似地牺牲演出,其实全为了慈善。",
                "世界上最长的姓名是简森·乔伊·亚历山大·比基·卡利斯勒·达夫·埃利奥特·福克斯·伊维鲁莫·马尔尼·梅尔斯·帕特森·汤普森·华莱士·普雷斯顿。",
        };
Segment segment = HanLP.newSegment().enableTranslatedNameRecognize(true);
for (String sentence : testCase)
{
    List<Term> termList = segment.seg(sentence);
    System.out.println(termList);
}

執行結果

[一/m, 桶/q, 冰/n, 水/n, 当头/d, 倒下/v, ,/w, 微软/ntc, 的/uj, 比尔盖茨/nrf, 、/w, Facebook/nx, 的/uj, 扎克伯格/nrf, 跟/p, 桑德/nrf, 博格/nrf, 、/w, 亚马逊/nrf, 的/uj, 贝索斯/nrf, 、/w, 苹果/n, 的/uj, 库克/nrf, 全都/d, 不惜/v, 湿/a, 身/ng, 入/v, 镜/ng, ,/w, 这些/r, 硅谷/n, 的/uj, 科技/n, 人/n, ,/w, 飞蛾扑火/nz, 似地/d, 牺牲/v, 演出/v, ,/w, 其实/d, 全/a, 为了/p, 慈善/a, 。/w]
[世界/n, 上/f, 最/d, 长/a, 的/uj, 姓名/n, 是/v, 简森·乔伊·亚历山大·比基·卡利斯勒·达夫·埃利奥特·福克斯·伊维鲁莫·马尔尼·梅尔斯·帕特森·汤普森·华莱士·普雷斯顿/nrf, 。/w]

日本人名識別

預設 關閉 了日本人名識別

String[] testCase = new String[]{
        "北川景子参演了林诣彬导演的《速度与激情3》",
        "林志玲亮相网友:确定不是波多野结衣?",
};
Segment segment = HanLP.newSegment().enableJapaneseNameRecognize(true);
for (String sentence : testCase)
{
    List<Term> termList = segment.seg(sentence);
    System.out.println(termList);
}

執行結果

[北川景子/nrj, 参演/v, 了/ul, 林诣彬/nr, 导演/n, 的/uj, 《/w, 速度/n, 与/p, 激情/n, 3/m, 》/w]
[林志玲/nr, 亮/v, 相/d, 网友/n, :/w, 确定/v, 不是/c, 波多野结衣/nrj, ?/w]

地名識別

預設關閉了地名識別

String[] testCase = new String[]{
        "武胜县新学乡政府大楼门前锣鼓喧天",
        "蓝翔给宁夏固原市彭阳县红河镇黑牛沟村捐赠了挖掘机",
};
Segment segment = HanLP.newSegment().enablePlaceRecognize(true);
for (String sentence : testCase)
{
    List<Term> termList = segment.seg(sentence);
    System.out.println(termList);
}

執行結果

[武胜县/ns, 新/a, 学/v, 乡政府/n, 大楼/n, 门前/s, 锣鼓喧天/i]
[蓝翔/nt, 给/p, 宁夏/ns, 固原市/ns, 彭阳县/ns, 红河镇/ns, 黑牛沟村/ns, 捐赠/v, 了/ul, 挖掘机/n]

機構名識別

預設關閉

String[] testCase = new String[]{
    "我在上海林原科技有限公司兼职工作,",
    "我经常在台川喜宴餐厅吃饭,",
    "偶尔去地中海影城看电影。",
};
Segment segment = HanLP.newSegment().enableOrganizationRecognize(true);
for (String sentence : testCase)
{
    List<Term> termList = segment.seg(sentence);
    System.out.println(termList);
}

執行結果

[我/r, 在/p, 上海林原科技有限公司/nt, 兼职/vn, 工作/vn, ,/w]
[我/r, 经常/d, 在/p, 台川喜宴餐厅/nt, 吃饭/v, ,/w]
[偶尔/d, 去/v, 地中海影城/nt, 看/v, 电影/n, 。/w]

關鍵詞

String content = "程序员(英文Programmer)是从事程序开发、维护的专业人员。一般将程序员分为程序设计人员和程序编码人员,但两者的界限并不非常清楚,特别是在中国。软件从业人员分为初级程序员、高级程序员、系统分析员和项目经理四大类。";
        List<String> keywordList = HanLP.extractKeyword(content, 5);
        System.out.println(keywordList);

執行結果

[程序员, 程序, 分为, 人员, 软件]

自動摘要

String document = "算法可大致分为基本算法、数据结构的算法、数论算法、计算几何的算法、图的算法、动态规划以及数值分析、加密算法、排序算法、检索算法、随机化算法、并行算法、厄米变形模型、随机森林算法。\n" +
        "算法可以宽泛的分为三类,\n" +
        "一,有限的确定性算法,这类算法在有限的一段时间内终止。他们可能要花很长时间来执行指定的任务,但仍将在一定的时间内终止。这类算法得出的结果常取决于输入值。\n" +
        "二,有限的非确定算法,这类算法在有限的时间内终止。然而,对于一个(或一些)给定的数值,算法的结果并不是唯一的或确定的。\n" +
        "三,无限的算法,是那些由于没有定义终止定义条件,或定义的条件无法由输入的数据满足而不终止运行的算法。通常,无限算法的产生是由于未能确定的定义终止条件。";
List<String> sentenceList = HanLP.extractSummary(document, 3);
System.out.println(sentenceList);

執行結果

[无限算法的产生是由于未能确定的定义终止条件, 这类算法在有限的时间内终止, 有限的非确定算法]

短詞語提取

String text = "算法工程师\n" +
                "算法(Algorithm)是一系列解决问题的清晰指令,也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题。不同的算法可能用不同的时间、空间或效率来完成同样的任务。一个算法的优劣可以用空间复杂度与时间复杂度来衡量。算法工程师就是利用算法处理事物的人。\n" +
                "\n" +
                "1职位简介\n" +
                "算法工程师是一个非常高端的职位;\n" +
                "专业要求:计算机、电子、通信、数学等相关专业;\n" +
                "学历要求:本科及其以上的学历,大多数是硕士学历及其以上;\n" +
                "语言要求:英语要求是熟练,基本上能阅读国外专业书刊;\n" +
                "必须掌握计算机相关知识,熟练使用仿真工具MATLAB等,必须会一门编程语言。\n" +
                "\n" +
                "2研究方向\n" +
                "视频算法工程师、图像处理算法工程师、音频算法工程师 通信基带算法工程师\n" +
                "\n" +
                "3目前国内外状况\n" +
                "目前国内从事算法研究的工程师不少,但是高级算法工程师却很少,是一个非常紧缺的专业工程师。算法工程师根据研究领域来分主要有音频/视频算法处理、图像技术方面的二维信息算法处理和通信物理层、雷达信号处理、生物医学信号处理等领域的一维信息算法处理。\n" +
                "在计算机音视频和图形图像技术等二维信息算法处理方面目前比较先进的视频处理算法:机器视觉成为此类算法研究的核心;另外还有2D转3D算法(2D-to-3D conversion),去隔行算法(de-interlacing),运动估计运动补偿算法(Motion estimation/Motion Compensation),去噪算法(Noise Reduction),缩放算法(scaling),锐化处理算法(Sharpness),超分辨率算法(Super Resolution),手势识别(gesture recognition),人脸识别(face recognition)。\n" +
                "在通信物理层等一维信息领域目前常用的算法:无线领域的RRM、RTT,传送领域的调制解调、信道均衡、信号检测、网络优化、信号分解等。\n" +
                "另外数据挖掘、互联网搜索算法也成为当今的热门方向。\n" +
                "算法工程师逐渐往人工智能方向发展。";
List<String> phraseList = HanLP.extractPhrase(text, 10);
System.out.println(phraseList);

執行結果

[算法工程师, 算法处理, 处理算法, 算法研究, 信号处理, 信息算法, 视频算法, 通信物理层, 解决问题, 互联网搜索算法]

拼音轉換

String text = "重载不是重任";
        List<Pinyin> pinyinList = HanLP.convertToPinyinList(text);
        System.out.print("原文,");
        for (char c : text.toCharArray())
        {
            System.out.printf("%c,", c);
        }
        System.out.println();

        System.out.print("拼音(数字音调),");
        for (Pinyin pinyin : pinyinList)
        {
            System.out.printf("%s,", pinyin);
        }
        System.out.println();

        System.out.print("拼音(符号音调),");
        for (Pinyin pinyin : pinyinList)
        {
            System.out.printf("%s,", pinyin.getPinyinWithToneMark());
        }
        System.out.println();

        System.out.print("拼音(无音调),");
        for (Pinyin pinyin : pinyinList)
        {
            System.out.printf("%s,", pinyin.getPinyinWithoutTone());
        }
        System.out.println();

        System.out.print("声调,");
        for (Pinyin pinyin : pinyinList)
        {
            System.out.printf("%s,", pinyin.getTone());
        }
        System.out.println();

        System.out.print("声母,");
        for (Pinyin pinyin : pinyinList)
        {
            System.out.printf("%s,", pinyin.getShengmu());
        }
        System.out.println();

        System.out.print("韵母,");
        for (Pinyin pinyin : pinyinList)
        {
            System.out.printf("%s,", pinyin.getYunmu());
        }
        System.out.println();

        System.out.print("输入法头,");
        for (Pinyin pinyin : pinyinList)
        {
            System.out.printf("%s,", pinyin.getHead());
        }
        System.out.println();

執行結果

原文,重,载,不,是,重,任,
拼音(数字音调),chong2,zai3,bu2,shi4,zhong4,ren4,
拼音(符号音调),chóng,zǎi,bú,shì,zhòng,rèn,
拼音(无音调),chong,zai,bu,shi,zhong,ren,
声调,2,3,2,4,4,4,
声母,ch,z,b,sh,zh,r,
韵母,ong,ai,u,i,ong,en,
输入法头,ch,z,b,sh,zh,r,

簡繁體轉換

System.out.println(HanLP.convertToTraditionalChinese("用笔记本电脑写程序"));
System.out.println(HanLP.convertToSimplifiedChinese("「以後等妳當上皇后,就能買士多啤梨慶祝了」"));

執行結果

用筆記本電腦寫程序
「以后等妳当上皇后,就能买士多啤梨庆祝了」

文句推薦

從一系列句子中,取得跟輸入詞語最相似的句子

Suggester suggester = new Suggester();
        String[] titleArray =
        (
                "威廉王子发表演说 呼吁保护野生动物\n" +
                "《时代》年度人物最终入围名单出炉 普京马云入选\n" +
                "“黑格比”横扫菲:菲吸取“海燕”经验及早疏散\n" +
                "日本保密法将正式生效 日媒指其损害国民知情权\n" +
                "英报告说空气污染带来“公共健康危机”"
        ).split("\\n");
        for (String title : titleArray)
        {
            suggester.addSentence(title);
        }

        System.out.println(suggester.suggest("发言", 1));       // 语义
        System.out.println(suggester.suggest("危机公共", 1));   // 字符
        System.out.println(suggester.suggest("mayun", 1));      // 拼音

執行結果

[威廉王子发表演说 呼吁保护野生动物]
[英报告说空气污染带来“公共健康危机”]
[《时代》年度人物最终入围名单出炉 普京马云入选]

語意距離

詞向量

String[] wordArray = new String[]
                {
                        "香蕉",
                        "苹果",
                        "白菜",
                        "水果",
                        "蔬菜",
                        "自行车",
                        "公交车",
                        "飞机",
                        "买",
                        "卖",
                        "购入",
                        "新年",
                        "春节",
                        "丢失",
                        "补办",
                        "办理",
                        "送给",
                        "寻找",
                        "孩子",
                        "教室",
                        "教师",
                        "会计",
                };
        for (String a : wordArray)
        {
            for (String b : wordArray)
            {
                System.out.println(a + "\t" + b + "\t之间的距离是\t" + CoreSynonymDictionary.distance(a, b));
            }
        }

執行結果


香蕉  香蕉  之间的距离是  0
香蕉  苹果  之间的距离是  19980
香蕉  白菜  之间的距离是  2628369
香蕉  水果  之间的距离是  32967
香蕉  蔬菜  之间的距离是  2630367
香蕉  自行车 之间的距离是  1854515628
香蕉  公交车 之间的距离是  1854535619
香蕉  飞机  之间的距离是  1857307833
香蕉  买   之间的距离是  39729797433
香蕉  卖   之间的距离是  39729897333
香蕉  购入  之间的距离是  39729797433
香蕉  新年  之间的距离是  4981789224
香蕉  春节  之间的距离是  4981789224
香蕉  丢失  之间的距离是  46784535633
香蕉  补办  之间的距离是  39205230527
香蕉  办理  之间的距离是  39205222533
香蕉  送给  之间的距离是  40831595534
香蕉  寻找  之间的距离是  41124601233
香蕉  孩子  之间的距离是  6734891367
香蕉  教室  之间的距离是  1548030420
香蕉  教师  之间的距离是  7516908567
香蕉  会计  之间的距离是  7547972472
苹果  香蕉  之间的距离是  19980
苹果  苹果  之间的距离是  0
苹果  白菜  之间的距离是  2608389
苹果  水果  之间的距离是  12987
苹果  蔬菜  之间的距离是  2610387
苹果  自行车 之间的距离是  1854535608
苹果  公交车 之间的距离是  1854555599
苹果  飞机  之间的距离是  1857327813
苹果  买   之间的距离是  39729817413
苹果  卖   之间的距离是  39729917313
苹果  购入  之间的距离是  39729817413
苹果  新年  之间的距离是  4981809204
苹果  春节  之间的距离是  4981809204
苹果  丢失  之间的距离是  46784555613
苹果  补办  之间的距离是  39205250507
苹果  办理  之间的距离是  39205242513
苹果  送给  之间的距离是  40831615514
苹果  寻找  之间的距离是  41124621213
苹果  孩子  之间的距离是  6734871387
苹果  教室  之间的距离是  1548050400
苹果  教师  之间的距离是  7516888587
苹果  会计  之间的距离是  7547952492
白菜  香蕉  之间的距离是  2628369
白菜  苹果  之间的距离是  2608389
白菜  白菜  之间的距离是  0
白菜  水果  之间的距离是  2595402
白菜  蔬菜  之间的距离是  1998
白菜  自行车 之间的距离是  1857143997
白菜  公交车 之间的距离是  1857163988
白菜  飞机  之间的距离是  1859936202
白菜  买   之间的距离是  39732425802
白菜  卖   之间的距离是  39732525702
白菜  购入  之间的距离是  39732425802
白菜  新年  之间的距离是  4984417593
白菜  春节  之间的距离是  4984417593
白菜  丢失  之间的距离是  46787164002
白菜  补办  之间的距离是  39207858896
白菜  办理  之间的距离是  39207850902
白菜  送给  之间的距离是  40834223903
白菜  寻找  之间的距离是  41127229602
白菜  孩子  之间的距离是  6732262998
白菜  教室  之间的距离是  1550658789
白菜  教师  之间的距离是  7514280198
白菜  会计  之间的距离是  7545344103
水果  香蕉  之间的距离是  32967
水果  苹果  之间的距离是  12987
水果  白菜  之间的距离是  2595402
水果  水果  之间的距离是  0
水果  蔬菜  之间的距离是  2597400
水果  自行车 之间的距离是  1854548595
水果  公交车 之间的距离是  1854568586
水果  飞机  之间的距离是  1857340800
水果  买   之间的距离是  39729830400
水果  卖   之间的距离是  39729930300
水果  购入  之间的距离是  39729830400
水果  新年  之间的距离是  4981822191
水果  春节  之间的距离是  4981822191
水果  丢失  之间的距离是  46784568600
水果  补办  之间的距离是  39205263494
水果  办理  之间的距离是  39205255500
水果  送给  之间的距离是  40831628501
水果  寻找  之间的距离是  41124634200
水果  孩子  之间的距离是  6734858400
水果  教室  之间的距离是  1548063387
水果  教师  之间的距离是  7516875600
水果  会计  之间的距离是  7547939505
蔬菜  香蕉  之间的距离是  2630367
蔬菜  苹果  之间的距离是  2610387
蔬菜  白菜  之间的距离是  1998
蔬菜  水果  之间的距离是  2597400
蔬菜  蔬菜  之间的距离是  0
蔬菜  自行车 之间的距离是  1857145995
蔬菜  公交车 之间的距离是  1857165986
蔬菜  飞机  之间的距离是  1859938200
蔬菜  买   之间的距离是  39732427800
蔬菜  卖   之间的距离是  39732527700
蔬菜  购入  之间的距离是  39732427800
蔬菜  新年  之间的距离是  4984419591
蔬菜  春节  之间的距离是  4984419591
蔬菜  丢失  之间的距离是  46787166000
蔬菜  补办  之间的距离是  39207860894
蔬菜  办理  之间的距离是  39207852900
蔬菜  送给  之间的距离是  40834225901
蔬菜  寻找  之间的距离是  41127231600
蔬菜  孩子  之间的距离是  6732261000
蔬菜  教室  之间的距离是  1550660787
蔬菜  教师  之间的距离是  7514278200
蔬菜  会计  之间的距离是  7545342105
自行车 香蕉  之间的距离是  1854515628
自行车 苹果  之间的距离是  1854535608
自行车 白菜  之间的距离是  1857143997
自行车 水果  之间的距离是  1854548595
自行车 蔬菜  之间的距离是  1857145995
自行车 自行车 之间的距离是  0
自行车 公交车 之间的距离是  19991
自行车 飞机  之间的距离是  2792205
自行车 买   之间的距离是  37875281805
自行车 卖   之间的距离是  37875381705
自行车 购入  之间的距离是  37875281805
自行车 新年  之间的距离是  3127273596
自行车 春节  之间的距离是  3127273596
自行车 丢失  之间的距离是  44930020005
自行车 补办  之间的距离是  37350714899
自行车 办理  之间的距离是  37350706905
自行车 送给  之间的距离是  38977079906
自行车 寻找  之间的距离是  39270085605
自行车 孩子  之间的距离是  8589406995
自行车 教室  之间的距离是  306485208
自行车 教师  之间的距离是  9371424195
自行车 会计  之间的距离是  9402488100
公交车 香蕉  之间的距离是  1854535619
公交车 苹果  之间的距离是  1854555599
公交车 白菜  之间的距离是  1857163988
公交车 水果  之间的距离是  1854568586
公交车 蔬菜  之间的距离是  1857165986
公交车 自行车 之间的距离是  19991
公交车 公交车 之间的距离是  0
公交车 飞机  之间的距离是  2772214
公交车 买   之间的距离是  37875261814
公交车 卖   之间的距离是  37875361714
公交车 购入  之间的距离是  37875261814
公交车 新年  之间的距离是  3127253605
公交车 春节  之间的距离是  3127253605
公交车 丢失  之间的距离是  44930000014
公交车 补办  之间的距离是  37350694908
公交车 办理  之间的距离是  37350686914
公交车 送给  之间的距离是  38977059915
公交车 寻找  之间的距离是  39270065614
公交车 孩子  之间的距离是  8589426986
公交车 教室  之间的距离是  306505199
公交车 教师  之间的距离是  9371444186
公交车 会计  之间的距离是  9402508091
飞机  香蕉  之间的距离是  1857307833
飞机  苹果  之间的距离是  1857327813
飞机  白菜  之间的距离是  1859936202
飞机  水果  之间的距离是  1857340800
飞机  蔬菜  之间的距离是  1859938200
飞机  自行车 之间的距离是  2792205
飞机  公交车 之间的距离是  2772214
飞机  飞机  之间的距离是  0
飞机  买   之间的距离是  37872489600
飞机  卖   之间的距离是  37872589500
飞机  购入  之间的距离是  37872489600
飞机  新年  之间的距离是  3124481391
飞机  春节  之间的距离是  3124481391
飞机  丢失  之间的距离是  44927227800
飞机  补办  之间的距离是  37347922694
飞机  办理  之间的距离是  37347914700
飞机  送给  之间的距离是  38974287701
飞机  寻找  之间的距离是  39267293400
飞机  孩子  之间的距离是  8592199200
飞机  教室  之间的距离是  309277413
飞机  教师  之间的距离是  9374216400
飞机  会计  之间的距离是  9405280305
买   香蕉  之间的距离是  39729797433
买   苹果  之间的距离是  39729817413
买   白菜  之间的距离是  39732425802
买   水果  之间的距离是  39729830400
买   蔬菜  之间的距离是  39732427800
买   自行车 之间的距离是  37875281805
买   公交车 之间的距离是  37875261814
买   飞机  之间的距离是  37872489600
买   买   之间的距离是  0
买   卖   之间的距离是  99900
买   购入  之间的距离是  0
买   新年  之间的距离是  34748008209
买   春节  之间的距离是  34748008209
买   丢失  之间的距离是  7054738200
买   补办  之间的距离是  524566906
买   办理  之间的距离是  524574900
买   送给  之间的距离是  1101798101
买   寻找  之间的距离是  1394803800
买   孩子  之间的距离是  46464688800
买   教室  之间的距离是  38181767013
买   教师  之间的距离是  47246706000
买   会计  之间的距离是  47277769905
卖   香蕉  之间的距离是  39729897333
卖   苹果  之间的距离是  39729917313
卖   白菜  之间的距离是  39732525702
卖   水果  之间的距离是  39729930300
卖   蔬菜  之间的距离是  39732527700
卖   自行车 之间的距离是  37875381705
卖   公交车 之间的距离是  37875361714
卖   飞机  之间的距离是  37872589500
卖   买   之间的距离是  99900
卖   卖   之间的距离是  0
卖   购入  之间的距离是  99900
卖   新年  之间的距离是  34748108109
卖   春节  之间的距离是  34748108109
卖   丢失  之间的距离是  7054638300
卖   补办  之间的距离是  524666806
卖   办理  之间的距离是  524674800
卖   送给  之间的距离是  1101698201
卖   寻找  之间的距离是  1394703900
卖   孩子  之间的距离是  46464788700
卖   教室  之间的距离是  38181866913
卖   教师  之间的距离是  47246805900
卖   会计  之间的距离是  47277869805
购入  香蕉  之间的距离是  39729797433
购入  苹果  之间的距离是  39729817413
购入  白菜  之间的距离是  39732425802
购入  水果  之间的距离是  39729830400
购入  蔬菜  之间的距离是  39732427800
购入  自行车 之间的距离是  37875281805
购入  公交车 之间的距离是  37875261814
购入  飞机  之间的距离是  37872489600
购入  买   之间的距离是  0
购入  卖   之间的距离是  99900
购入  购入  之间的距离是  0
购入  新年  之间的距离是  34748008209
购入  春节  之间的距离是  34748008209
购入  丢失  之间的距离是  7054738200
购入  补办  之间的距离是  524566906
购入  办理  之间的距离是  524574900
购入  送给  之间的距离是  1101798101
购入  寻找  之间的距离是  1394803800
购入  孩子  之间的距离是  46464688800
购入  教室  之间的距离是  38181767013
购入  教师  之间的距离是  47246706000
购入  会计  之间的距离是  47277769905
新年  香蕉  之间的距离是  4981789224
新年  苹果  之间的距离是  4981809204
新年  白菜  之间的距离是  4984417593
新年  水果  之间的距离是  4981822191
新年  蔬菜  之间的距离是  4984419591
新年  自行车 之间的距离是  3127273596
新年  公交车 之间的距离是  3127253605
新年  飞机  之间的距离是  3124481391
新年  买   之间的距离是  34748008209
新年  卖   之间的距离是  34748108109
新年  购入  之间的距离是  34748008209
新年  新年  之间的距离是  0
新年  春节  之间的距离是  0
新年  丢失  之间的距离是  41802746409
新年  补办  之间的距离是  34223441303
新年  办理  之间的距离是  34223433309
新年  送给  之间的距离是  35849806310
新年  寻找  之间的距离是  36142812009
新年  孩子  之间的距离是  11716680591
新年  教室  之间的距离是  3433758804
新年  教师  之间的距离是  12498697791
新年  会计  之间的距离是  12529761696
春节  香蕉  之间的距离是  4981789224
春节  苹果  之间的距离是  4981809204
春节  白菜  之间的距离是  4984417593
春节  水果  之间的距离是  4981822191
春节  蔬菜  之间的距离是  4984419591
春节  自行车 之间的距离是  3127273596
春节  公交车 之间的距离是  3127253605
春节  飞机  之间的距离是  3124481391
春节  买   之间的距离是  34748008209
春节  卖   之间的距离是  34748108109
春节  购入  之间的距离是  34748008209
春节  新年  之间的距离是  0
春节  春节  之间的距离是  0
春节  丢失  之间的距离是  41802746409
春节  补办  之间的距离是  34223441303
春节  办理  之间的距离是  34223433309
春节  送给  之间的距离是  35849806310
春节  寻找  之间的距离是  36142812009
春节  孩子  之间的距离是  11716680591
春节  教室  之间的距离是  3433758804
春节  教师  之间的距离是  12498697791
春节  会计  之间的距离是  12529761696
丢失  香蕉  之间的距离是  46784535633
丢失  苹果  之间的距离是  46784555613
丢失  白菜  之间的距离是  46787164002
丢失  水果  之间的距离是  46784568600
丢失  蔬菜  之间的距离是  46787166000
丢失  自行车 之间的距离是  44930020005
丢失  公交车 之间的距离是  44930000014
丢失  飞机  之间的距离是  44927227800
丢失  买   之间的距离是  7054738200
丢失  卖   之间的距离是  7054638300
丢失  购入  之间的距离是  7054738200
丢失  新年  之间的距离是  41802746409
丢失  春节  之间的距离是  41802746409
丢失  丢失  之间的距离是  0
丢失  补办  之间的距离是  7579305106
丢失  办理  之间的距离是  7579313100
丢失  送给  之间的距离是  5952940099
丢失  寻找  之间的距离是  5659934400
丢失  孩子  之间的距离是  53519427000
丢失  教室  之间的距离是  45236505213
丢失  教师  之间的距离是  54301444200
丢失  会计  之间的距离是  54332508105
补办  香蕉  之间的距离是  39205230527
补办  苹果  之间的距离是  39205250507
补办  白菜  之间的距离是  39207858896
补办  水果  之间的距离是  39205263494
补办  蔬菜  之间的距离是  39207860894
补办  自行车 之间的距离是  37350714899
补办  公交车 之间的距离是  37350694908
补办  飞机  之间的距离是  37347922694
补办  买   之间的距离是  524566906
补办  卖   之间的距离是  524666806
补办  购入  之间的距离是  524566906
补办  新年  之间的距离是  34223441303
补办  春节  之间的距离是  34223441303
补办  丢失  之间的距离是  7579305106
补办  补办  之间的距离是  0
补办  办理  之间的距离是  7994
补办  送给  之间的距离是  1626365007
补办  寻找  之间的距离是  1919370706
补办  孩子  之间的距离是  45940121894
补办  教室  之间的距离是  37657200107
补办  教师  之间的距离是  46722139094
补办  会计  之间的距离是  46753202999
办理  香蕉  之间的距离是  39205222533
办理  苹果  之间的距离是  39205242513
办理  白菜  之间的距离是  39207850902
办理  水果  之间的距离是  39205255500
办理  蔬菜  之间的距离是  39207852900
办理  自行车 之间的距离是  37350706905
办理  公交车 之间的距离是  37350686914
办理  飞机  之间的距离是  37347914700
办理  买   之间的距离是  524574900
办理  卖   之间的距离是  524674800
办理  购入  之间的距离是  524574900
办理  新年  之间的距离是  34223433309
办理  春节  之间的距离是  34223433309
办理  丢失  之间的距离是  7579313100
办理  补办  之间的距离是  7994
办理  办理  之间的距离是  0
办理  送给  之间的距离是  1626373001
办理  寻找  之间的距离是  1919378700
办理  孩子  之间的距离是  45940113900
办理  教室  之间的距离是  37657192113
办理  教师  之间的距离是  46722131100
办理  会计  之间的距离是  46753195005
送给  香蕉  之间的距离是  40831595534
送给  苹果  之间的距离是  40831615514
送给  白菜  之间的距离是  40834223903
送给  水果  之间的距离是  40831628501
送给  蔬菜  之间的距离是  40834225901
送给  自行车 之间的距离是  38977079906
送给  公交车 之间的距离是  38977059915
送给  飞机  之间的距离是  38974287701
送给  买   之间的距离是  1101798101
送给  卖   之间的距离是  1101698201
送给  购入  之间的距离是  1101798101
送给  新年  之间的距离是  35849806310
送给  春节  之间的距离是  35849806310
送给  丢失  之间的距离是  5952940099
送给  补办  之间的距离是  1626365007
送给  办理  之间的距离是  1626373001
送给  送给  之间的距离是  0
送给  寻找  之间的距离是  293005699
送给  孩子  之间的距离是  47566486901
送给  教室  之间的距离是  39283565114
送给  教师  之间的距离是  48348504101
送给  会计  之间的距离是  48379568006
寻找  香蕉  之间的距离是  41124601233
寻找  苹果  之间的距离是  41124621213
寻找  白菜  之间的距离是  41127229602
寻找  水果  之间的距离是  41124634200
寻找  蔬菜  之间的距离是  41127231600
寻找  自行车 之间的距离是  39270085605
寻找  公交车 之间的距离是  39270065614
寻找  飞机  之间的距离是  39267293400
寻找  买   之间的距离是  1394803800
寻找  卖   之间的距离是  1394703900
寻找  购入  之间的距离是  1394803800
寻找  新年  之间的距离是  36142812009
寻找  春节  之间的距离是  36142812009
寻找  丢失  之间的距离是  5659934400
寻找  补办  之间的距离是  1919370706
寻找  办理  之间的距离是  1919378700
寻找  送给  之间的距离是  293005699
寻找  寻找  之间的距离是  0
寻找  孩子  之间的距离是  47859492600
寻找  教室  之间的距离是  39576570813
寻找  教师  之间的距离是  48641509800
寻找  会计  之间的距离是  48672573705
孩子  香蕉  之间的距离是  6734891367
孩子  苹果  之间的距离是  6734871387
孩子  白菜  之间的距离是  6732262998
孩子  水果  之间的距离是  6734858400
孩子  蔬菜  之间的距离是  6732261000
孩子  自行车 之间的距离是  8589406995
孩子  公交车 之间的距离是  8589426986
孩子  飞机  之间的距离是  8592199200
孩子  买   之间的距离是  46464688800
孩子  卖   之间的距离是  46464788700
孩子  购入  之间的距离是  46464688800
孩子  新年  之间的距离是  11716680591
孩子  春节  之间的距离是  11716680591
孩子  丢失  之间的距离是  53519427000
孩子  补办  之间的距离是  45940121894
孩子  办理  之间的距离是  45940113900
孩子  送给  之间的距离是  47566486901
孩子  寻找  之间的距离是  47859492600
孩子  孩子  之间的距离是  0
孩子  教室  之间的距离是  8282921787
孩子  教师  之间的距离是  782017200
孩子  会计  之间的距离是  813081105
教室  香蕉  之间的距离是  1548030420
教室  苹果  之间的距离是  1548050400
教室  白菜  之间的距离是  1550658789
教室  水果  之间的距离是  1548063387
教室  蔬菜  之间的距离是  1550660787
教室  自行车 之间的距离是  306485208
教室  公交车 之间的距离是  306505199
教室  飞机  之间的距离是  309277413
教室  买   之间的距离是  38181767013
教室  卖   之间的距离是  38181866913
教室  购入  之间的距离是  38181767013
教室  新年  之间的距离是  3433758804
教室  春节  之间的距离是  3433758804
教室  丢失  之间的距离是  45236505213
教室  补办  之间的距离是  37657200107
教室  办理  之间的距离是  37657192113
教室  送给  之间的距离是  39283565114
教室  寻找  之间的距离是  39576570813
教室  孩子  之间的距离是  8282921787
教室  教室  之间的距离是  0
教室  教师  之间的距离是  9064938987
教室  会计  之间的距离是  9096002892
教师  香蕉  之间的距离是  7516908567
教师  苹果  之间的距离是  7516888587
教师  白菜  之间的距离是  7514280198
教师  水果  之间的距离是  7516875600
教师  蔬菜  之间的距离是  7514278200
教师  自行车 之间的距离是  9371424195
教师  公交车 之间的距离是  9371444186
教师  飞机  之间的距离是  9374216400
教师  买   之间的距离是  47246706000
教师  卖   之间的距离是  47246805900
教师  购入  之间的距离是  47246706000
教师  新年  之间的距离是  12498697791
教师  春节  之间的距离是  12498697791
教师  丢失  之间的距离是  54301444200
教师  补办  之间的距离是  46722139094
教师  办理  之间的距离是  46722131100
教师  送给  之间的距离是  48348504101
教师  寻找  之间的距离是  48641509800
教师  孩子  之间的距离是  782017200
教师  教室  之间的距离是  9064938987
教师  教师  之间的距离是  0
教师  会计  之间的距离是  31063905
会计  香蕉  之间的距离是  7547972472
会计  苹果  之间的距离是  7547952492
会计  白菜  之间的距离是  7545344103
会计  水果  之间的距离是  7547939505
会计  蔬菜  之间的距离是  7545342105
会计  自行车 之间的距离是  9402488100
会计  公交车 之间的距离是  9402508091
会计  飞机  之间的距离是  9405280305
会计  买   之间的距离是  47277769905
会计  卖   之间的距离是  47277869805
会计  购入  之间的距离是  47277769905
会计  新年  之间的距离是  12529761696
会计  春节  之间的距离是  12529761696
会计  丢失  之间的距离是  54332508105
会计  补办  之间的距离是  46753202999
会计  办理  之间的距离是  46753195005
会计  送给  之间的距离是  48379568006
会计  寻找  之间的距离是  48672573705
会计  孩子  之间的距离是  813081105
会计  教室  之间的距离是  9096002892
会计  教师  之间的距离是  31063905
会计  会计  之间的距离是  0

依存句法分析

CoNLLSentence sentence = HanLP.parseDependency("徐先生还具体帮助他确定了把画雄鹰、松鼠和麻雀作为主攻目标。");
        System.out.println(sentence);
        // 可以方便地遍历它
        for (CoNLLWord word : sentence)
        {
            System.out.printf("%s --(%s)--> %s\n", word.LEMMA, word.DEPREL, word.HEAD.LEMMA);
        }
        // 也可以直接拿到数组,任意顺序或逆序遍历
        CoNLLWord[] wordArray = sentence.getWordArray();
        for (int i = wordArray.length - 1; i >= 0; i--)
        {
            CoNLLWord word = wordArray[i];
            System.out.printf("%s --(%s)--> %s\n", word.LEMMA, word.DEPREL, word.HEAD.LEMMA);
        }
        // 还可以直接遍历子树,从某棵子树的某个节点一路遍历到虚根
        CoNLLWord head = wordArray[12];
        while ((head = head.HEAD) != null)
        {
            if (head == CoNLLWord.ROOT) System.out.println(head.LEMMA);
            else System.out.printf("%s --(%s)--> ", head.LEMMA, head.DEPREL);
        }

執行結果

1   徐先生 徐先生 nh  nr  _   4   主谓关系    _   _
2   还   还   d   d   _   4   状中结构    _   _
3   具体  具体  a   ad  _   4   状中结构    _   _
4   帮助  帮助  v   v   _   0   核心关系    _   _
5   他   他   r   r   _   4   兼语  _   _
6   确定  确定  v   v   _   4   动宾关系    _   _
7   了   了   u   u   _   6   右附加关系   _   _
8   把   把   p   p   _   15  状中结构    _   _
9   画   画   v   v   _   8   介宾关系    _   _
10  雄鹰  雄鹰  n   n   _   9   动宾关系    _   _
11  、   、   wp  w   _   12  标点符号    _   _
12  松鼠  松鼠  n   n   _   10  并列关系    _   _
13  和   和   c   c   _   14  左附加关系   _   _
14  麻雀  麻雀  n   n   _   10  并列关系    _   _
15  作为  作为  v   v   _   6   动宾关系    _   _
16  主攻  主攻  v   vn  _   17  定中关系    _   _
17  目标  目标  n   n   _   15  动宾关系    _   _
18  。   。   wp  w   _   4   标点符号    _   _

徐先生 --(主谓关系)--> 帮助
还 --(状中结构)--> 帮助
具体 --(状中结构)--> 帮助
帮助 --(核心关系)--> ##核心##
他 --(兼语)--> 帮助
确定 --(动宾关系)--> 帮助
了 --(右附加关系)--> 确定
把 --(状中结构)--> 作为
画 --(介宾关系)--> 把
雄鹰 --(动宾关系)--> 画
、 --(标点符号)--> 松鼠
松鼠 --(并列关系)--> 雄鹰
和 --(左附加关系)--> 麻雀
麻雀 --(并列关系)--> 雄鹰
作为 --(动宾关系)--> 确定
主攻 --(定中关系)--> 目标
目标 --(动宾关系)--> 作为
。 --(标点符号)--> 帮助
。 --(标点符号)--> 帮助
目标 --(动宾关系)--> 作为
主攻 --(定中关系)--> 目标
作为 --(动宾关系)--> 确定
麻雀 --(并列关系)--> 雄鹰
和 --(左附加关系)--> 麻雀
松鼠 --(并列关系)--> 雄鹰
、 --(标点符号)--> 松鼠
雄鹰 --(动宾关系)--> 画
画 --(介宾关系)--> 把
把 --(状中结构)--> 作为
了 --(右附加关系)--> 确定
确定 --(动宾关系)--> 帮助
他 --(兼语)--> 帮助
帮助 --(核心关系)--> ##核心##
具体 --(状中结构)--> 帮助
还 --(状中结构)--> 帮助
徐先生 --(主谓关系)--> 帮助
麻雀 --(并列关系)--> 雄鹰 --(动宾关系)--> 画 --(介宾关系)--> 把 --(状中结构)--> 作为 --(动宾关系)--> 确定 --(动宾关系)--> 帮助 --(核心关系)--> ##核心##

References

自然语言处理:HanLP

HanLP 1.x

多功能的自然語言處理工具 —— HanLP

《自然语言处理入门》详细笔记

Python繁體中文自然語言處理-HanLP安裝及測試

OpenCC-to-HanLP

HanLP支持繁體中文和簡中字典較好的字典

python如何使用HanLP,LTP,jieba中文分詞庫

商用 LTP 需要付费

LTP github

2021/06/21

OpenCC

OpenCC 是 Open Chinese Convert 的縮寫,是轉換中文簡繁的工具

安裝

pip install opencc-python-reimplemented

轉換的模式有以下這幾種:

  • hk2s: 繁體中文 (香港) -> 簡體中文
  • s2hk: 簡體中文 -> 繁體中文 (香港)
  • s2t: 簡體中文 -> 繁體中文
  • s2tw: 簡體中文 -> 繁體中文 (台灣)
  • s2twp: 簡體中文 -> 繁體中文 (台灣, 包含慣用詞轉換)
  • t2hk: 繁體中文 -> 繁體中文 (香港)
  • t2s: 繁體中文 -> 簡體中文
  • t2tw: 繁體中文 -> 繁體中文 (台灣)
  • tw2s: 繁體中文 (台灣) -> 簡體中文
  • tw2sp: 繁體中文 (台灣) -> 簡體中文 (包含慣用詞轉換 )

有兩種使用方式

  • 在 python 程式中使用

    from opencc import OpenCC
    
    tw2s = OpenCC("tw2s")
    tw2sp = OpenCC("tw2sp")
    s2tw = OpenCC("s2tw")
    s2twp = OpenCC("s2twp")
    
    print( tw2s.convert("香煙(英語:Cigarette),為煙草製品的一種。滑鼠是一種很常見及常用的電腦輸入設備。") )
    
    # 香烟(英语:Cigarette),为烟草制品的一种。滑鼠是一种很常见及常用的电脑输入设备。
    
    print( tw2sp.convert("香煙(英語:Cigarette),為煙草製品的一種。滑鼠是一種很常見及常用的電腦輸入設備。") )
    
    # 香烟(英语:Cigarette),为烟草制品的一种。鼠标是一种很常见及常用的电脑输入设备。
    
    print( tw2s.convert("人工智慧(英語:artificial intelligence,縮寫為AI)亦稱智械、機器智慧,指由人製造出來的機器所表現出來的智慧。通常人工智慧是指透過普通電腦程式來呈現人類智慧的技術。") )
    # 人工智慧(英语:artificial intelligence,缩写为AI)亦称智械、机器智慧,指由人制造出来的机器所表现出来的智慧。通常人工智慧是指透过普通电脑程式来呈现人类智慧的技术。
    
    print( tw2sp.convert("人工智慧(英語:artificial intelligence,縮寫為AI)亦稱智械、機器智慧,指由人製造出來的機器所表現出來的智慧。通常人工智慧是指透過普通電腦程式來呈現人類智慧的技術。") )
    # 人工智能(英语:artificial intelligence,缩写为AI)亦称智械、机器智能,指由人制造出来的机器所表现出来的智能。通常人工智能是指透过普通电脑程序来呈现人类智能的技术。
    
  • Command line

    s$ python -m opencc --help
    usage: __main__.py [-h] [-i <file>] [-o <file>] [-c <conversion>]
                       [--in-enc <encoding>] [--out-enc <encoding>]
    
    optional arguments:
      -h, --help            show this help message and exit
      -i <file>, --input <file>
                            Read original text from <file>. (default: None)
      -o <file>, --output <file>
                            Write converted text to <file>. (default: None)
      -c <conversion>, --config <conversion>
                            Conversion (default: None)
      --in-enc <encoding>   Encoding for input (default: UTF-8)
      --out-enc <encoding>  Encoding for output (default: UTF-8)
    python -m opencc -c tw2s -i s_input_file.txt -o tw_output_file.txt
    
    python -m opencc -c tw2sp -i s_input_file.txt -o twp_output_file.txt

References

開放中文轉換(Pure Python)

2021/06/07

如何在 CentOS 7 安裝 Heartbeat

Heartbeat 3.x 版拆分為 heartbeat, cluster-glue, resource-agent 三個部分,必須要分開安裝。

  • 確認 hostname

    #vim /etc/hosts,增加兩行 (Server A 和 Server B 上都要各設定兩行)
    192.168.1.35 kokome1
    192.168.1.36 kokome2
  • 安裝編譯需要的套件,以及 kernel-devel-$(uname -r) kernel-headers-$(uname -r)

yum install -y bzip2 autoconf automake libtool glib2-devel libxml2-devel bzip2-devel libtool-ltdl-devel asciidoc libuuid-devel psmisc
  • 安裝 cluster-glue
wget http://hg.linux-ha.org/glue/archive/0a7add1d9996.tar.bz2

tar jxvf 0a7add1d9996.tar.bz2
cd Reusable-Cluster-Components-glue--0a7add1d9996/
groupadd haclient
useradd -g haclient hacluster
./autogen.sh
./configure --prefix=/usr/local/heartbeat/
make
make install

cd ..
  • 安裝 Resource Agents
wget https://github.com/ClusterLabs/resource-agents/archive/v3.9.6.tar.gz
tar zxvf v3.9.6.tar.gz
cd resource-agents-3.9.6/
./autogen.sh
export CFLAGS="$CFLAGS -I/usr/local/heartbeat/include -L/usr/local/heartbeat/lib"
./configure --prefix=/usr/local/heartbeat/

echo "/usr/local/heartbeat/lib" > /etc/ld.so.conf.d/heartbeat.conf
ldconfig

make
make install

cd ..
  • 安裝 heartbeat
wget http://hg.linux-ha.org/heartbeat-STABLE_3_0/archive/958e11be8686.tar.bz2
tar jxvf 958e11be8686.tar.bz2
cd Heartbeat-3-0-958e11be8686
./bootstrap
export CFLAGS="$CFLAGS -I/usr/local/heartbeat/include -L/usr/local/heartbeat/lib"
./configure --prefix=/usr/local/heartbeat/

vi /usr/local/heartbeat/include/heartbeat/glue_config.h
/*define HA_HBCONF_DIR “/usr/local/heartbeat/etc/ha.d/”*/   (這行用/**/註釋掉)

make
make install

cd ..
  • 複製設定
ln -svf /usr/local/heartbeat/lib64/heartbeat/plugins/RAExec/* /usr/local/heartbeat/lib/heartbeat/plugins/RAExec/
ln -svf /usr/local/heartbeat/lib64/heartbeat/plugins/* /usr/local/heartbeat/lib/heartbeat/plugins/

cp /usr/local/heartbeat/share/doc/heartbeat/ha.cf  /usr/local/heartbeat/etc/ha.d
cp /usr/local/heartbeat/share/doc/heartbeat/authkeys /usr/local/heartbeat/etc/ha.d
cp /usr/local/heartbeat/share/doc/heartbeat/haresources /usr/local/heartbeat/etc/ha.d
  • 修改 authkeys

vim /usr/local/heartbeat/etc/ha.d/authkeys #在最後加上

auth 1
1 crc
chmod 600 /usr/local/heartbeat/etc/ha.d/authkeys
  • 設定 ha.cf

因為這個檔案說明太多,尋找和修改不方便,執行下面把原來的換個名稱,把 ha.cf.old 檔案過濾掉註解,剩下的輸出到 ha.cf 檔案中再修改

mv /usr/local/heartbeat/etc/ha.d/ha.cf /usr/local/heartbeat/etc/ha.d/ha.cf.old
sed -e '/^#/d' -e '/^$/d' /usr/local/heartbeat/etc/ha.d/ha.cf.old > /usr/local/heartbeat/etc/ha.d/ha.cf

然後再去修改 /usr/local/heartbeat/etc/ha.d/ha.cf 內容 (參數說明去看剛剛備份的 /etc/ha.d/ha.cf.old)

vi /usr/local/heartbeat/etc/ha.d/ha.cf

logfile /var/log/ha.log
logfacility local0
keepalive 2
deadtime 30
initdead 120
bcast eth0
udpport 694
auto_failback on
node kokome1
node kokome2
ping 192.168.1.1
respawn hacluster /usr/local/heartbeat/libexec/heartbeat/ipfail
apiauth ipfail gid=haclient uid=hacluster

node 值必須和兩台主機的 uname -n 執行結果相符合 可以用 ping gateway ip 來偵測 logfile 是設定 heartbeat 執行情況的 log

  • 設定 haresources

vim /usr/local/heartbeat/etc/ha.d/haresources,最後加入一行

kokome1 IPaddr::192.168.1.13/24/eth0 tomcat httpd

第1個參數是 HA 的主要電腦的 hostname
第2個參數是虛擬介面 IP
第3個參數服務名稱
  • 把 heartbeat 設定全部複製到 Server B 上
scp -r /usr/local/heartbeat/etc/ha.d/ root@192.168.1.12:/usr/local/heartbeat/etc/ha.d/
  • 啟動 heartbeat

    service heartbeat restart
    
    chkconfig heartbeat on
    chkconfig --add heartbeat
    chkconfig --level 2345 heartbeat on
    chkconfig --list heartbeat
    
  • 如果 ifconfig 沒有看到 Virtual IP 的資訊 就改用以下指令

    ip -o -f inet addr show
  • ssh 免密碼

    yum -y install openssh-clients
    
    kokome1:
    mkdir -p /root/.ssh
    cd /root/.ssh
    ssh-keygen -t dsa
    按enter直到完成
    
    (id_kokome1.pub為自己辨識用的名稱)
    scp id_dsa.pub 192.168.1.12:/root/.ssh/id_kokome1.pub
    
    ssh 192.168.1.12
    cd /root/.ssh/
    cat id_kokome1.pub >> authorized_keys
    完成ssh免密碼
    
    kokome2:
    cd /root/.ssh
    ssh-keygen -t dsa
    按enter直到完成
    
    (id_kokome2.pub為自己辨識用的名稱)
    scp id_dsa.pub 192.168.1.11:/root/.ssh/id_kokome2.pub
    
    ssh 192.168.1.11
    cd /root/.ssh/
    cat id_kokome2.pub >> authorized_keys
    完成ssh免密碼
  • 測試

1) Server A 正常時 用瀏覽器連上 http://192.168.1.11,應該會出現 "I am kokome 1" 用瀏覽器連上 http://192.168.1.12,應該會出現 "連線失敗" 一類訊息 用瀏覽器連上 http://192.168.1.13,應該會出現 "I am kokome 1"

(2) Server A 當掉時 假設 Server A 當了,心跳 (heartbeat) 停了,請執行

service heartbeat stop

或把 Server A 關機

(工作接管可能需要 1,2分鐘)

用瀏覽器連上 http://192.168.1.11,應該會出現 "連線失敗" 一類訊息 用瀏覽器連上 http://192.168.1.12,應該會出現 "I am kokome 2" 用瀏覽器連上 http://192.168.1.13,應該會出現 "I am kokome 2"

(3) Server A 又復原

假設 Server A 復原,心跳 (heartbeat) 復原,請執行

service heartbeat start

(工作接管可能需要 1,2分鐘)

用瀏覽器連上 http://192.168.1.11,應該會出現 "I am kokome 1" 用瀏覽器連上 http://192.168.1.12,應該會出現 "連線失敗" 一類訊息 用瀏覽器連上 http://192.168.1.13,應該會出現 "I am kokome 1"

這樣表示測試成功

  • 發生 error

ERROR: Cannot locate resource script httpd

解決方法

cp /usr/sbin/apachectl /usr/local/heartbeat/etc/ha.d/resource.d/httpd

References

Current Linux-HA Release Downloads

centos7.5部署heartbeat+DRBD+mysql高可用方案

CentOS7數據庫架構之NFS+heartbeat+DRBD(親測,詳解)

Heartbeat 3.0.3 介绍及rpm