InputStream
as a list of Strings,
46 | * one entry per line.
47 | *
48 | * @param input the InputStream
to read from, not null
49 | * @return the list of Strings, never null
50 | * @throws NullPointerException if the input is null
51 | * @throws IOException if an I/O error occurs
52 | */
53 | public static ListInputStream
as a byte[]
.
68 | *
69 | * This method buffers the input internally, so there is no need to use a
70 | * BufferedInputStream
.
71 | *
72 | * @param input the InputStream
to read from
73 | * @return the requested byte array
74 | * @throws NullPointerException if the input is null
75 | * @throws IOException if an I/O error occurs
76 | */
77 | public static byte[] toByteArray(final InputStream input) throws IOException {
78 | try (final ByteArrayOutputStream output = new ByteArrayOutputStream()) {
79 | int n;
80 | byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
81 | while (EOF != (n = input.read(buffer))) {
82 | output.write(buffer, 0, n);
83 | }
84 | return output.toByteArray();
85 | }
86 | }
87 |
88 | /**
89 | * Gets the contents of an InputStream
as a int array.
90 | *
91 | * This method buffers the input internally, so there is no need to use a
92 | * BufferedInputStream
.
93 | *
94 | * @param input the InputStream
to read from
95 | * @return the requested int array
96 | * @throws NullPointerException if the input is null
97 | * @throws IOException if an I/O error occurs
98 | */
99 | public static int[] toIntArray(final InputStream input) throws IOException {
100 | byte[] bytes = toByteArray(input);
101 | IntBuffer intBuffer = ByteBuffer.wrap(bytes)
102 | .order(ByteOrder.LITTLE_ENDIAN)
103 | .asIntBuffer();
104 | int[] array = new int[intBuffer.remaining()];
105 | intBuffer.get(array);
106 | return array;
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/main/java/io/github/yizhiru/thulac4j/util/ModelPaths.java:
--------------------------------------------------------------------------------
1 | package io.github.yizhiru.thulac4j.util;
2 |
3 | /**
4 | * 模型文件路径名
5 | */
6 | public final class ModelPaths {
7 |
8 | /**
9 | * 核心字符类型词典
10 | */
11 | public static final String CORE_CHAR_PATH = "/dicts/core_char.dict";
12 |
13 | /**
14 | * 地名词典
15 | */
16 | public static final String NS_DICT_PATH = "dicts/ns.dict";
17 |
18 | /**
19 | * 成语、习语、谚语词典
20 | */
21 | public static final String IDIOM_DICT_PATH = "dicts/idiom.dict";
22 |
23 | /**
24 | * 停用词词典
25 | */
26 | public static final String STOP_WORDS_DICT_PATH = "dicts/stop_words.dict";
27 |
28 | public static final String NS_BIN_PATH = "/models/ns_dat.bin";
29 | public static final String IDIOM_BIN_PATH = "/models/idiom_dat.bin";
30 | public static final String STOP_WORDS_BIN_PATH = "/models/stop_dat.bin";
31 |
32 | /**
33 | * 繁体到简体字符映射
34 | */
35 | public static final String T2S_PATH = "/models/t2s.dat";
36 |
37 | /**
38 | * 分词模块权重
39 | */
40 | public static final String SEGMENTER_WEIGHT_PATH = "/models/cws_model.bin";
41 |
42 | /**
43 | * 分词模块特征
44 | */
45 | public static final String SEGMENTER_FEATURE_PATH = "/models/cws_dat.bin";
46 |
47 | /**
48 | * 分词模块label
49 | */
50 | public static final String SEGMENTER_LABEL_PATH = "/models/cws_label.txt";
51 |
52 | /**
53 | * 词性标注模块label
54 | */
55 | public static final String POS_TAGGING_LABEL_PATH = "/models/model_c_label.txt";
56 | }
57 |
--------------------------------------------------------------------------------
/src/test/java/io/github/yizhiru/thulac4j/POSTaggerTest.java:
--------------------------------------------------------------------------------
1 | package io.github.yizhiru.thulac4j;
2 |
3 | import io.github.yizhiru.thulac4j.term.TokenItem;
4 | import org.junit.Test;
5 |
6 | import java.io.IOException;
7 | import java.nio.charset.StandardCharsets;
8 | import java.util.stream.Collectors;
9 |
10 | import static io.github.yizhiru.thulac4j.SPChineseTokenizerTest.POS_FEATURES_PATH;
11 | import static io.github.yizhiru.thulac4j.SPChineseTokenizerTest.POS_WEIGHTS_PATH;
12 | import static io.github.yizhiru.thulac4j.SegmenterTest.SENTENCES;
13 | import static org.junit.Assert.assertEquals;
14 |
15 | public class POSTaggerTest {
16 |
17 | @Test
18 | public void tagging() throws IOException {
19 | String[] expectedResults = new String[]{
20 | "因/p",
21 | "",
22 | "",
23 | "UTF/x -/w 8/m",
24 | "iphone5/x",
25 | "鲜芋仙/nz 3/m",
26 | "枪杆子/n 中/f 出/v 政权/n",
27 | "两/m 块/q 五/m 一/m 套/q ,/w 三/m 块/q 八/m 一/m 斤/q ,/w 四/m 块/q 七/m 一/m 本/q ,/w 五/m 块/q 六/m 一/m 条/q",
28 | "RT/x @/w laoshipukong/x :/w 27日/t ,/w",
29 | "AT&T/nz 是/v 一/m 件/q 不错/a 的/u 公司/n ,/w 给/p 你/r 发/v offer/x 了/u 吗/u ?/w",
30 | "4/m 个/q 月/n 赚/v 了/u 20%/m 多/m",
31 | "仅/d 1/m 只/q ,/w 为/v 0.9923/m 元/q",
32 | "Just/n one/nz space/x ,/w or/ns all/nz such/x spaces/x ?/w",
33 | "倒模/v ,/w 替身/v 算/v 什么/r ?/w 钟汉良/np 、/w ab/np 《/w 孤芳不自赏/id 》/w 抠图/n 来/v 充数/v",
34 | "奥迪/nz CEO/x 违规/v 遭批/v 大众/n 表示/v 不/d 会/v 解雇/v",
35 | "找/v 小姐/n",
36 | "找/v 小妹/n",
37 | "学生/n 妹/n",
38 | "职业/n 狐狸精/n",
39 | "男/a 公关/n",
40 | "上门/v",
41 | "抽獎/v",
42 | "好/a 声音/n",
43 | "好/a 聲音/n",
44 | "夢/n 之/u 声/g",
45 | "夢之聲/id",
46 | "訂票/n",
47 | "改簽/v",
48 | "熱线/n",
49 | "熱線/n",
50 | "热線/a",
51 | "電话/n",
52 | "電話/n",
53 | "醫院/n",
54 | "代刷/v",
55 | "撲剋牌/nz",
56 | "137-1234-1234/m",
57 | "这/r 是/v 一个/m 伸手不见五指/i 的/u 黑夜/n 。/w 我/r 叫/v 孙悟空/np ,/w 我/r 爱/v 北京/ns ,/w 我/r 爱/v Python/x 和/c C/x +/w" +
58 | " +/w 。/w",
59 | "我/r 不/d 喜欢/v 日本/ns 和服/n 。/w",
60 | "雷猴/v 回归/v 人间/n 。/w",
61 | "工信处/n 女/a 干事/n 每月/r 经过/p 下属/v 科室/n 都/d 要/v 亲口/d 交代/v 24/m 口/q 交换机/n 等/u 技术性/n 器件/n 的/u 安装/v 工作/v",
62 | "我/r 需要/v 廉/g 租/v 房/n",
63 | "永和/nz 服装/n 饰品/n 有限公司/n",
64 | "我/r 爱/v 北京/ns 天安门/ns",
65 | "abc/n",
66 | "隐马尔可夫/np",
67 | "雷猴/v 是/v 个/q 好/a 网站/n",
68 | "“/w ,/w ”/w 和/c “/w SOFTware/x (/w 软件/n )/w ”/w 两/m 部分/n 组成/v",
69 | "草泥马/n 和/c 欺/g 实马/n 是/v 今年/t 的/u 流行/v 词汇/n",
70 | "伊藤/nz 洋华堂/n 总府店/n",
71 | "中国/ns 科学院/n 计算/v 技术/n 研究所/n",
72 | "罗密欧/ns 与/c 朱丽叶/np",
73 | "我/r 购买/v 了/u 道具/n 和/c 服装/n",
74 | "PS/x :/w 我/r 觉得/v 开源/v 有/v 一个/m 好处/n ,/w 就/d 是/v 能够/v 敦促/v 自己/r 不断/d 改进/v ,/w 避免/v 敞帚自珍/id",
75 | "湖北省/ns 石首市/ns",
76 | "湖北省/ns 十堰市/ns",
77 | "总经理/n 完成/v 了/u 这/r 件/q 事情/n",
78 | "电脑/n 修好/v 了/u",
79 | "做好/v 了/u 这/r 件/q 事情/n 就/d 一了百了/i 了/u",
80 | "人们/n 审美/v 的/u 观点/n 是/v 不同/a 的/u",
81 | "我们/r 买/v 了/u 一个/m 美/a 的/u 空调/n",
82 | "线程/n 初始化/v 时/g 我们/r 要/v 注意/v",
83 | "一个/m 分子/n 是/v 由/p 好多/m 原子组/n 织成/v 的/u",
84 | "祝/v 你/r 马到功成/i",
85 | "他/r 掉/v 进/v 了/u 无/v 底洞/n 里/f",
86 | "中国/ns 的/u 首都/n 是/v 北京/ns",
87 | "孙君意/np",
88 | "外交部/ni 发言人/n 马朝旭/np",
89 | "领导人/n 会议/n 和/c 第四/m 届/q 东亚/ns 峰会/n",
90 | "在/p 过去/t 的/u 这/r 五/m 年/q",
91 | "还/d 需要/v 很/d 长/a 的/u 路/n 要/v 走/v",
92 | "60/m 周年/q 首都/n 阅兵/n",
93 | "你好/id 人们/n 审美/v 的/u 观点/n 是/v 不同/a 的/u",
94 | "买/v 水果/n 然后/c 来/v 世博园/j",
95 | "买/v 水果/n 然后/c 去/v 世博园/j",
96 | "但是/c 后来/t 我/r 才/d 知道/v 你/r 是/v 对/a 的/u",
97 | "存在/v 即/c 合理/a",
98 | "的/u 的/u 的/u 的/u 的/u 在/p 的/u 的/u 的/u 的/u 就/d 以/p 和和/nz 和/c",
99 | "I/v love/x 你/r ,/w 不以为耻/i ,/w 反/d 以为/v rong/x",
100 | "hello/x 你好/id 人们/n 审美/v 的/u 观点/n 是/v 不同/a 的/u",
101 | "很/d 好/a 但/c 主要/d 是/v 基于/p 网页/n 形式/n",
102 | "为什么/r 我/r 不/d 能/v 拥有/v 想/v 要/v 的/u 生活/v",
103 | "后来/t 我/r 才/d",
104 | "此次/r 来/v 中国/ns 是/v 为了/p",
105 | "使用/v 了/u 它/r 就/d 可以/v 解决/v 一些/m 问题/n",
106 | ",/w 使用/v 了/u 它/r 就/d 可以/v 解决/v 一些/m 问题/n",
107 | "其实/d 使用/v 了/u 它/r 就/d 可以/v 解决/v 一些/m 问题/n",
108 | "好人/n 使用/v 了/u 它/r 就/d 可以/v 解决/v 一些/m 问题/n",
109 | "是/v 因为/p 和/p 国家/n",
110 | "老年/t 搜索/v 还/d 支持/v",
111 | "干脆/d 就/d 把/p 那/r 部/q 蒙/v 人/n 的/u 闲法/n 给/p 废/v 了/u 拉倒/v !/w RT/x @/w laoshipukong/x :/w 27日/t ,/w " +
112 | "全国/n 人大/j 常委会/j 第三/m 次/q 审议/v 侵权/v 责任法/n 草案/n ,/w 删除/v 了/u 有关/v 医疗/n 损害/v 责任/n “/w 举证/v 倒置/v" +
113 | " ”/w 的/u 规定/n 。/w 在/p 医患/n 纠纷/n 中/f 本/d 已/d 处于/v 弱势/n 地位/n 的/u 消费者/n 由此/d 将/d 陷入/v 万劫不复/i " +
114 | "的/u 境地/n 。/w",
115 | "他/r 说/v 的/u 确实/a 在理/a",
116 | "长春/ns 市长/n 春节/t 讲话/n",
117 | "结婚/v 的/u 和/c 尚未/d 结婚/v 的/u",
118 | "结合/v 成分子/n 时/g",
119 | "旅游/v 和/c 服务/v 是/v 最/d 好/a 的/u",
120 | "这/r 件/q 事情/n 的确/d 是/v 我/r 的/u 错/n",
121 | "供/v 大家/r 参考/v 指正/v",
122 | "哈尔滨/ns 政府/n 公布/v 塌/v 桥/n 原因/n",
123 | "我/r 在/p 机场/n 入口处/n",
124 | "邢永臣/np 摄影/v 报道/v",
125 | "BP/x 神经/n 网络/n 如何/r 训练/v 才/d 能/v 在/p 分类/v 时/g 增加/v 区/n 分度/n ?/w",
126 | "南京市/ns 长江/ns 大桥/n",
127 | "应/v 一些/m 使用者/n 的/u 建议/n ,/w 也/d 为了/p 便于/v 利用/v NiuTrans/x 用于/v SMT/x 研究/v",
128 | "长春市/ns 长春/ns 药店/n",
129 | "邓颖超/np 生前/t 最/d 喜欢/v 的/u 衣服/n",
130 | "胡锦涛/np 是/v 热爱/v 世界/n 和平/n 的/u 政治局/n 常委/n",
131 | "程序员/n 祝海林/np 和/c 朱会震/np 是/v 在/p 孙健/np 的/u 左面/f 和/c 右面/f ,/w 范凯/np 在/p 最/d 右面/f ./w 再/d 往/p 左/f 是/v " +
132 | "李松洪/np",
133 | "一次性/d 交/v 多少/r 钱/n",
134 | "小/a 和/c 尚/d 留/v 了/u 一个/m 像/p 大/a 和尚/n 一样/a 的/u 和尚/n 头/n",
135 | "我/r 是/v 中华人民共和国/ns 公民/n ;/w 我/r 爸爸/n 是/v 共和党/n 党员/n ;/w 地铁/n 和平/n 门站/n",
136 | "张晓梅/np 去/v 人民/n 医院/n 做/v 了/u 个/q B/x 超然/a 后/f 去/v 买/v 了/u 件/q T/m 恤/q",
137 | "C/x +/w +/w 和/c c/g #/w 是/v 什么/r 关系/n ?/w 11/m +/w 122/m =/w 133/m ,/w 是/v 吗/u ?/w PI/x =/w 3.14159/m",
138 | "你/r 认识/v 那个/r 和/c 主席/n 握手/v 的/u 的/u 哥/j 吗/u ?/w 他/r 开/v 一/m 辆/q 黑色/n 的士/n 。/w",
139 | "2017-10-13/m 给/p 你/r 发/v offer/x 了/u 吗/u ?/w 27日/t 发/v iphone5/x 了/u 吗/u",
140 | "本报/r 讯/g 深圳市/ns 海王/nz 生物/n 工程/n 股份/n 有限公司/n 二○○○/m 年度/n 增/v 发/v A/x 股/n 路/n 演/v 推介会/n 日前/t 在/p 北京/ns 举行/v",
141 | "共同/d 创造/v 美好/a 的/u 新/a 世纪/n ——/w 2001年/t 新年/t 贺词/n",
142 | };
143 |
144 | POSTagger posTagger = new POSTagger(POS_WEIGHTS_PATH, POS_FEATURES_PATH);
145 | posTagger.enableTitleWord();
146 | for (int i = 0; i < SENTENCES.length; i++) {
147 | String actual = posTagger.tagging(SENTENCES[i])
148 | .stream()
149 | .map(TokenItem::toString)
150 | .collect(Collectors.joining(" "));
151 | assertEquals(expectedResults[i], actual);
152 | }
153 |
154 | long length = 0L;
155 | long start = System.currentTimeMillis();
156 | for (int i = 0; i < 100; ++i) {
157 | for (String sentence : SENTENCES) {
158 | posTagger.tagging(sentence);
159 | length += sentence.getBytes(StandardCharsets.UTF_8).length;
160 | }
161 | }
162 | long elapsed = (System.currentTimeMillis() - start);
163 | System.out.println(String.format("time elapsed: %d ms, rate: %.2f kb/s.",
164 | elapsed, (length * 1.0) / 1024.0f / (elapsed * 1.0 / 1000.0f)));
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/src/test/java/io/github/yizhiru/thulac4j/SPChineseTokenizerTest.java:
--------------------------------------------------------------------------------
1 | package io.github.yizhiru.thulac4j;
2 |
3 | import io.github.yizhiru.thulac4j.perceptron.StructuredPerceptronClassifier;
4 | import org.junit.Test;
5 | import org.junit.runner.RunWith;
6 | import org.powermock.core.classloader.annotations.PrepareForTest;
7 | import org.powermock.modules.junit4.PowerMockRunner;
8 | import org.powermock.reflect.internal.WhiteboxImpl;
9 |
10 | import java.io.FileInputStream;
11 | import java.util.Arrays;
12 |
13 | import static org.junit.Assert.assertArrayEquals;
14 | import static org.junit.Assert.assertEquals;
15 |
16 | @RunWith(PowerMockRunner.class)
17 | @PrepareForTest(StructuredPerceptronClassifier.class)
18 | public class SPChineseTokenizerTest {
19 |
20 | /**
21 | * Segmenter weights model path.
22 | */
23 | public static final String SEG_WEIGHTS_PATH = "models/cws_model.bin";
24 |
25 | /**
26 | * Segmenter features path.
27 | */
28 | public static final String SEG_FEATURES_PATH = "models/cws_dat.bin";
29 |
30 | public static final String SEG_LABELS_PATH = "models/cws_label.txt";
31 |
32 | /**
33 | * POSTagger weights model path.
34 | */
35 | public static final String POS_WEIGHTS_PATH = "models/model_c_model.bin";
36 |
37 | /**
38 | * POSTagger features path.
39 | */
40 | public static final String POS_FEATURES_PATH = "models/model_c_dat.bin";
41 |
42 | public static final String POS_LABELS_PATH = "models/model_c_label.txt";
43 |
44 | @Test
45 | public void setPreviousTrans() throws Exception {
46 | SPChineseTokenizer tokenizer = new SPChineseTokenizer(
47 | new FileInputStream(SEG_WEIGHTS_PATH),
48 | new FileInputStream(SEG_FEATURES_PATH),
49 | new FileInputStream(SEG_LABELS_PATH));
50 | StructuredPerceptronClassifier classifier = WhiteboxImpl.getInternalState(tokenizer, "classifier");
51 | int[][] previousTrans = WhiteboxImpl.invokeMethod(
52 | tokenizer,
53 | "setPreviousTransitions",
54 | new Class>[]{String[].class},
55 | (Object) classifier.getLabelValues());
56 |
57 | assertEquals("[[1, 2], [0, 3], [1, 2], [0, 3]]",
58 | Arrays.deepToString(previousTrans));
59 |
60 | tokenizer = new SPChineseTokenizer(
61 | new FileInputStream(POS_WEIGHTS_PATH),
62 | new FileInputStream(POS_FEATURES_PATH),
63 | new FileInputStream(POS_LABELS_PATH));
64 | classifier = WhiteboxImpl.getInternalState(tokenizer, "classifier");
65 | previousTrans = WhiteboxImpl.invokeMethod(
66 | tokenizer,
67 | "setPreviousTransitions",
68 | new Class>[]{String[].class},
69 | (Object) classifier.getLabelValues());
70 | assertEquals("[1, 2, 4, 5, 7, 10, 13, 15, 17, 18, 19, 23, 25, 27, " +
71 | "30, 32, 33, 34, 35, 36, 37, 38, 39, 41, 44, 45, 48, 50, 53, " +
72 | "56, 57, 59, 61, 63, 67, 69, 72, 74, 76, 80, 81, 82, 83, 88, " +
73 | "89, 90, 91, 95]",
74 | Arrays.toString(previousTrans[0]));
75 | assertEquals("[0, 20]", Arrays.toString(previousTrans[1]));
76 | assertEquals("[54, 55]", Arrays.toString(previousTrans[56]));
77 | assertEquals("[93, 94]", Arrays.toString(previousTrans[95]));
78 | }
79 | }
--------------------------------------------------------------------------------
/src/test/java/io/github/yizhiru/thulac4j/SegmenterTest.java:
--------------------------------------------------------------------------------
1 | package io.github.yizhiru.thulac4j;
2 |
3 | import org.junit.FixMethodOrder;
4 | import org.junit.Test;
5 | import org.junit.runners.MethodSorters;
6 |
7 | import java.nio.charset.StandardCharsets;
8 | import java.util.Arrays;
9 | import java.util.stream.Collectors;
10 |
11 | import static org.junit.Assert.assertEquals;
12 |
13 | @FixMethodOrder(MethodSorters.NAME_ASCENDING)
14 | public class SegmenterTest {
15 |
16 | static final String[] SENTENCES = new String[]{
17 | "因",
18 | " ",
19 | "",
20 | "UTF-8",
21 | "iphone5",
22 | "鲜芋仙 3",
23 | "枪杆子中出政权",
24 | "两块五一套,三块八一斤,四块七一本,五块六一条",
25 | "RT @laoshipukong : 27日,",
26 | "AT&T是一件不错的公司,给你发offer了吗?",
27 | "4个月赚了20%多",
28 | "仅1只,为0.9923元",
29 | "Just one space, or all such spaces?",
30 | "倒模,替身算什么?钟汉良、ab《孤芳不自赏》抠图来充数",
31 | "奥迪CEO违规遭批 大众表示不会解雇",
32 | "找小姐",
33 | "找小妹",
34 | "学生妹",
35 | "职业狐狸精",
36 | "男公关",
37 | "上门",
38 | "抽獎",
39 | "好声音",
40 | "好聲音",
41 | "夢之声",
42 | "夢之聲",
43 | "訂票",
44 | "改簽",
45 | "熱线",
46 | "熱線",
47 | "热線",
48 | "電话",
49 | "電話",
50 | "醫院",
51 | "代刷",
52 | "撲剋牌",
53 | "137-1234-1234",
54 | "这是一个伸手不见五指的黑夜。我叫孙悟空,我爱北京,我爱Python和C++。",
55 | "我不喜欢日本和服。",
56 | "雷猴回归人间。",
57 | "工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作",
58 | "我需要廉租房",
59 | "永和服装饰品有限公司",
60 | "我爱北京天安门",
61 | "abc",
62 | "隐马尔可夫",
63 | "雷猴是个好网站",
64 | "“,”和“SOFTware(软件)”两部分组成",
65 | "草泥马和欺实马是今年的流行词汇",
66 | "伊藤洋华堂总府店",
67 | "中国科学院计算技术研究所",
68 | "罗密欧与朱丽叶",
69 | "我购买了道具和服装",
70 | "PS: 我觉得开源有一个好处,就是能够敦促自己不断改进,避免敞帚自珍",
71 | "湖北省石首市",
72 | "湖北省十堰市",
73 | "总经理完成了这件事情",
74 | "电脑修好了",
75 | "做好了这件事情就一了百了了",
76 | "人们审美的观点是不同的",
77 | "我们买了一个美的空调",
78 | "线程初始化时我们要注意",
79 | "一个分子是由好多原子组织成的",
80 | "祝你马到功成",
81 | "他掉进了无底洞里",
82 | "中国的首都是北京",
83 | "孙君意",
84 | "外交部发言人马朝旭",
85 | "领导人会议和第四届东亚峰会",
86 | "在过去的这五年",
87 | "还需要很长的路要走",
88 | "60周年首都阅兵",
89 | "你好人们审美的观点是不同的",
90 | "买水果然后来世博园",
91 | "买水果然后去世博园",
92 | "但是后来我才知道你是对的",
93 | "存在即合理",
94 | "的的的的的在的的的的就以和和和",
95 | "I love你,不以为耻,反以为rong",
96 | "hello你好人们审美的观点是不同的",
97 | "很好但主要是基于网页形式",
98 | "为什么我不能拥有想要的生活",
99 | "后来我才",
100 | "此次来中国是为了",
101 | "使用了它就可以解决一些问题",
102 | ",使用了它就可以解决一些问题",
103 | "其实使用了它就可以解决一些问题",
104 | "好人使用了它就可以解决一些问题",
105 | "是因为和国家",
106 | "老年搜索还支持",
107 | "干脆就把那部蒙人的闲法给废了拉倒!RT @laoshipukong : 27日,全国人大常委会第三次审议" +
108 | "侵权责任法草案,删除了有关医疗损害责任“举证倒置”的规定。在医患纠纷中本已处于" +
109 | "弱势地位的消费者由此将陷入万劫不复的境地。 ",
110 | "他说的确实在理",
111 | "长春市长春节讲话",
112 | "结婚的和尚未结婚的",
113 | "结合成分子时",
114 | "旅游和服务是最好的",
115 | "这件事情的确是我的错",
116 | "供大家参考指正",
117 | "哈尔滨政府公布塌桥原因",
118 | "我在机场入口处",
119 | "邢永臣摄影报道",
120 | "BP神经网络如何训练才能在分类时增加区分度?",
121 | "南京市长江大桥",
122 | "应一些使用者的建议,也为了便于利用NiuTrans用于SMT研究",
123 | "长春市长春药店",
124 | "邓颖超生前最喜欢的衣服",
125 | "胡锦涛是热爱世界和平的政治局常委",
126 | "程序员祝海林和朱会震是在孙健的左面和右面, 范凯在最右面.再往左是李松洪",
127 | "一次性交多少钱",
128 | "小和尚留了一个像大和尚一样的和尚头",
129 | "我是中华人民共和国公民;我爸爸是共和党党员; 地铁和平门站",
130 | "张晓梅去人民医院做了个B超然后去买了件T恤",
131 | "C++和c#是什么关系?11+122=133,是吗?PI=3.14159",
132 | "你认识那个和主席握手的的哥吗?他开一辆黑色的士。",
133 | "2017-10-13给你发offer了吗?27日发iphone5了吗",
134 | "本报讯深圳市海王生物工程股份有限公司二○○○年度增发A股路演推介会日前在北京举行",
135 | "共同创造美好的新世纪——2001年新年贺词",
136 | };
137 |
138 | @Test
139 | public void segment() {
140 | String[] expectedResults = new String[]{
141 | "因",
142 | "",
143 | "",
144 | "UTF - 8",
145 | "iphone5",
146 | "鲜芋仙 3",
147 | "枪杆子 中 出 政权",
148 | "两 块 五一套 , 三 块 八一斤 , 四 块 七 一 本 , 五 块 六 一 条",
149 | "RT @ laoshipukong : 27日 ,",
150 | "AT&T 是 一 件 不错 的 公司 , 给 你 发 offer 了 吗 ?",
151 | "4 个 月 赚 了 20% 多",
152 | "仅 1 只 , 为 0.9923 元",
153 | "Just one space , or all such spaces ?",
154 | "倒模 , 替身 算 什么 ? 钟汉良 、 ab 《 孤芳不自赏 》 抠 图 来 充数",
155 | "奥迪 CEO 违规 遭 批 大众 表示 不 会 解雇",
156 | "找 小姐",
157 | "找 小 妹",
158 | "学生 妹",
159 | "职业 狐狸 精",
160 | "男 公关",
161 | "上门",
162 | "抽獎",
163 | "好 声音",
164 | "好 聲音",
165 | "夢 之 声",
166 | "夢 之 聲",
167 | "訂票",
168 | "改簽",
169 | "熱线",
170 | "熱線",
171 | "热線",
172 | "電话",
173 | "電話",
174 | "醫院",
175 | "代刷",
176 | "撲剋牌",
177 | "137-1234-1234",
178 | "这 是 一个 伸手不见五指 的 黑夜 。 我 叫 孙悟空 , 我 爱 北京 , 我 爱 Python 和 C + + 。",
179 | "我 不 喜欢 日本 和服 。",
180 | "雷猴 回归 人间 。",
181 | "工信 处女 干事 每月 经过 下属 科室 都 要 亲口 交代 24 口 交换机 等 技术性 器件 的 安装 工作",
182 | "我 需要 廉 租 房",
183 | "永 和 服装 饰品 有限公司",
184 | "我 爱 北京 天安门",
185 | "abc",
186 | "隐马尔可夫",
187 | "雷猴 是 个 好 网站",
188 | "“ , ” 和 “ SOFTware ( 软件 ) ” 两 部分 组成",
189 | "草泥马 和 欺实马 是 今年 的 流行 词汇",
190 | "伊藤 洋华堂 总府 店",
191 | "中国 科学院 计算 技术 研究所",
192 | "罗密欧 与 朱丽叶",
193 | "我 购买 了 道具 和 服装",
194 | "PS : 我 觉得 开源 有 一个 好处 , 就是 能够 敦促 自己 不断 改进 , 避免 敞帚自珍",
195 | "湖北省 石首市",
196 | "湖北省 十堰市",
197 | "总经理 完成 了 这 件 事情",
198 | "电脑 修好 了",
199 | "做 好 了 这 件 事情 就 一了百了 了",
200 | "人们 审美 的 观点 是 不同 的",
201 | "我们 买 了 一个 美 的 空调",
202 | "线程 初始化 时 我们 要 注意",
203 | "一个 分子 是 由 好多 原子 组织 成 的",
204 | "祝 你 马到功成",
205 | "他 掉 进 了 无 底洞 里",
206 | "中国 的 首都 是 北京",
207 | "孙君意",
208 | "外交部 发言人 马朝旭",
209 | "领导人 会议 和 第四 届 东亚 峰会",
210 | "在 过去 的 这 五 年",
211 | "还 需要 很 长 的 路 要 走",
212 | "60 周年 首都 阅兵",
213 | "你好 人们 审美 的 观点 是 不同 的",
214 | "买 水 果然 后来 世博园",
215 | "买 水果 然后 去世 博园",
216 | "但是 后来 我 才 知道 你 是 对 的",
217 | "存在 即 合理",
218 | "的 的 的 的 的 在 的 的 的 的 就 以 和 和 和",
219 | "I love 你 , 不以为耻 , 反 以为 rong",
220 | "hello 你好 人们 审美 的 观点 是 不同 的",
221 | "很 好 但 主要 是 基于 网页 形式",
222 | "为什么 我 不 能 拥有 想 要 的 生活",
223 | "后来 我 才",
224 | "此次 来 中国 是 为了",
225 | "使用 了 它 就 可以 解决 一些 问题",
226 | ", 使用 了 它 就 可以 解决 一些 问题",
227 | "其实 使用 了 它 就 可以 解决 一些 问题",
228 | "好人 使用 了 它 就 可以 解决 一些 问题",
229 | "是 因为 和 国家",
230 | "老年 搜索 还 支持",
231 | "干脆 就 把 那 部 蒙人 的 闲法 给 废 了 拉倒 ! RT @ laoshipukong : 27日 , 全国 人大 常委会 第三 次 审议 侵权 责任法 草案 , 删除 了 有关 医疗 损害 " +
232 | "责任 “ 举证 倒置 ” 的 规定 。 在 医患 纠纷 中 本 已 处于 弱势 地位 的 消费者 由此 将 陷入 万劫不复 的 境地 。",
233 | "他 说 的 确实 在理",
234 | "长春 市长 春节 讲话",
235 | "结婚 的 和 尚未 结婚 的",
236 | "结合 成分子 时",
237 | "旅游 和 服务 是 最 好 的",
238 | "这 件 事情 的确 是 我 的 错",
239 | "供 大家 参考 指正",
240 | "哈尔滨 政府 公布 塌桥 原因",
241 | "我 在 机场 入口处",
242 | "邢永臣 摄影 报道",
243 | "BP 神经 网络 如何 训练 才 能 在 分类 时 增加 区 分度 ?",
244 | "南京市 长江 大桥",
245 | "应 一些 使用者 的 建议 , 也 为了 便于 利用 NiuTrans 用于 SMT 研究",
246 | "长春市 长春 药店",
247 | "邓颖超 生前 最 喜欢 的 衣服",
248 | "胡锦涛 是 热爱 世界 和平 的 政治局 常委",
249 | "程序员 祝海林 和 朱会震 是 在 孙健 的 左面 和 右面 , 范凯 在 最 右 面 . 再 往 左 是 李松洪",
250 | "一次性 交 多少 钱",
251 | "小 和尚 留 了 一个 像 大 和 尚 一样 的 和尚 头",
252 | "我 是 中华人民共和国 公民 ; 我 爸爸 是 共和党 党员 ; 地铁 和平门站",
253 | "张晓梅 去 人民 医院 做 了 个 B 超然 后 去 买 了 件 T 恤",
254 | "C + + 和 c # 是 什么 关系 ? 11 + 122 = 133 , 是 吗 ? PI = 3.14159",
255 | "你 认识 那个 和 主席 握手 的 的 哥 吗 ? 他 开 一 辆 黑色 的 士 。",
256 | "2017-10-13 给 你 发 offer 了 吗 ? 27日 发 iphone5 了 吗",
257 | "本报 讯 深圳市 海王 生物 工程 股份 有限公司 二○○○ 年度 增 发 A 股 路演 推介会 日前 在 北京 举行",
258 | "共同 创造 美好 的 新 世纪 —— 2001年 新年 贺词",
259 | };
260 |
261 | Segmenter.enableTitleWord();
262 | for (int i = 0; i < SENTENCES.length; i++) {
263 | String actual = String.join(" ", Segmenter.segment(SENTENCES[i]));
264 | assertEquals(expectedResults[i], actual);
265 | }
266 |
267 | long length = 0L;
268 | long start = System.currentTimeMillis();
269 | for (int i = 0; i < 1000; ++i) {
270 | for (String sentence : SENTENCES) {
271 | Segmenter.segment(sentence);
272 | length += sentence.getBytes(StandardCharsets.UTF_8).length;
273 | }
274 | }
275 | long elapsed = (System.currentTimeMillis() - start);
276 | System.out.println(String.format("time elapsed: %d ms, rate: %.2f kb/s.",
277 | elapsed, (length * 1.0) / 1024.0f / (elapsed * 1.0 / 1000.0f)));
278 | }
279 |
280 | @Test
281 | public void addUserWords() {
282 | Segmenter.addUserWords(Arrays.asList("中国风", "淡雅茗香"));
283 | assertEquals("浓浓的,中国风,淡雅茗香,古风",
284 | String.join(",", Segmenter.segment("浓浓的中国风 淡雅茗香古风")));
285 | }
286 |
287 | @Test
288 | public void zFilterStopWords() {
289 | Segmenter.enableFilterStopWords();
290 | assertEquals("我,能,做,的,事,绝不,推诿,到,下,一",
291 | String.join(",", Segmenter.segment("此时我能做的事,绝不推诿到下一时刻;")));
292 | assertEquals("H,歌,你,的,猎豹,要是,有,你,的,嘴,那么,硬,有,多,好",
293 | String.join(",", Segmenter.segment("【H歌】你的猎豹要是有你的嘴那么硬有多好")));
294 | assertEquals("沿江,高铁,雏形,初,现,湖北,要,做,祖国,立交桥",
295 | String.join(",", Segmenter.segment("沿江高铁雏形初现:湖北要做“祖国立交桥”")));
296 | assertEquals("学,得,好,却,总是,考,不好,是,回,事",
297 | String.join(",", Segmenter.segment("「学得好却总是考不好」是怎么回事?")));
298 | }
299 | }
300 |
--------------------------------------------------------------------------------
/src/test/java/io/github/yizhiru/thulac4j/common/DoubleArrayTrieTest.java:
--------------------------------------------------------------------------------
1 | package io.github.yizhiru.thulac4j.common;
2 |
3 | import io.github.yizhiru.thulac4j.util.ModelPaths;
4 | import org.junit.Test;
5 |
6 | import java.io.IOException;
7 | import java.nio.file.Files;
8 | import java.nio.file.Paths;
9 | import java.util.List;
10 | import java.util.Set;
11 | import java.util.stream.Collectors;
12 |
13 | import static org.junit.Assert.*;
14 |
15 | public class DoubleArrayTrieTest {
16 |
17 | @Test
18 | public void isMatched() throws IOException {
19 | DoubleArrayTrie dat = DoubleArrayTrie.loadDat("." + ModelPaths.NS_BIN_PATH);
20 | assertTrue(dat.isPrefixMatched("黑龙江"));
21 | assertTrue(dat.isWordMatched("黑龙江"));
22 | assertTrue(dat.isWordMatched("齐齐哈尔"));
23 | assertTrue(dat.isWordMatched("名古屋"));
24 | assertTrue(dat.isWordMatched("克拉约瓦"));
25 | assertTrue(dat.isWordMatched("10月9日街"));
26 | assertTrue(dat.isWordMatched("鸡公?"));
27 | assertTrue(dat.isWordMatched("齐白石纪念馆"));
28 | assertTrue(dat.isWordMatched("龙格伦吉里"));
29 | assertTrue(dat.isWordMatched("特德本-圣玛丽"));
30 | assertFalse(dat.isWordMatched("首乌"));
31 | }
32 |
33 | @Test
34 | public void serialize() throws IOException {
35 | String[] dictPaths = new String[]{
36 | ModelPaths.IDIOM_DICT_PATH,
37 | ModelPaths.NS_DICT_PATH,
38 | ModelPaths.STOP_WORDS_DICT_PATH,
39 | };
40 | String[] binPaths = new String[]{
41 | "." + ModelPaths.IDIOM_BIN_PATH,
42 | "." + ModelPaths.NS_BIN_PATH,
43 | "." + ModelPaths.STOP_WORDS_BIN_PATH,
44 | };
45 | for (int i = 0; i < dictPaths.length; i++) {
46 | DoubleArrayTrie expect = DoubleArrayTrie.make(dictPaths[i]);
47 | expect.serialize(binPaths[i]);
48 | DoubleArrayTrie actual = DoubleArrayTrie.loadDat(binPaths[i]);
49 |
50 | assertEquals(expect.size(), actual.size());
51 | for (int j = 0; j < expect.size(); j++) {
52 | assertEquals(expect.getBaseByIndex(j), actual.getBaseByIndex(j));
53 | assertEquals(expect.getCheckByIndex(j), actual.getCheckByIndex(j));
54 | }
55 | }
56 | }
57 |
58 | @Test
59 | public void make() throws IOException {
60 | String[] paths = new String[]{
61 | ModelPaths.NS_DICT_PATH,
62 | ModelPaths.IDIOM_DICT_PATH,
63 | ModelPaths.STOP_WORDS_DICT_PATH
64 | };
65 | for (String path : paths) {
66 | List