├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── docs
└── wiki
│ ├── Home.md
│ └── media
│ └── 1.png
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── mindflow
│ │ └── py4j
│ │ ├── Converter.java
│ │ ├── PinyinConverter.java
│ │ ├── exception
│ │ └── IllegalPinyinException.java
│ │ ├── util
│ │ ├── ArrayUtils.java
│ │ ├── IoUtils.java
│ │ └── StringUtils.java
│ │ └── voc
│ │ └── Py4jDictionary.java
└── resources
│ └── META-INF
│ └── vocabulary
│ └── py4j.txt
└── test
└── java
└── com
└── mindflow
└── py4j
├── PinyinConverterTest.java
└── ThreadSafeTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # maven ignore
2 | *target/
3 | !tools/*.jar
4 | *.war
5 | *.zip
6 | *.tar
7 | *.tar.gz
8 |
9 | # Java class files
10 | *.class
11 |
12 | # eclipse ignore
13 | *.settings/
14 | .project
15 | .classpath
16 |
17 | # idea ignore
18 | .idea/
19 | *.ipr
20 | *.iml
21 | *.iws
22 |
23 | # temp ignore
24 | *.log
25 | *.log.*
26 | *.cache
27 | *.diff
28 | *.patch
29 | *.tmp
30 |
31 | # system ignore
32 | .DS_Store
33 | Thumbs.db
34 |
35 | sublime-project
36 | sublime-project.sublime-workspace
37 |
38 | coverage-report/
39 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Kitty
2 | [](https://www.apache.org/licenses/LICENSE-2.0) [](https://github.com/TFrise/py4j/releases) [](https://travis-ci.org/TFrise/py4j)
3 |
4 | ## Overview
5 | A open-source Java library for converting Chinese to Pinyin.
6 |
7 | ## Features
8 | * solve Chinese polyphone
9 | * support external custom extension dictionary
10 |
11 | ## maven dependency
12 | ```
13 |
14 | com.mindflow
15 | py4j
16 | 1.0.0
17 |
18 | ```
19 |
20 | ## Usage
21 | ### 1. single char
22 | ```
23 | Converter converter = new PinyinConverter();
24 |
25 | char[] chs = {'长', '行', '藏', '度', '阿', '佛', '2', 'A', 'a'};
26 | for(char ch : chs){
27 | String[] arr_py = converter.getPinyin(ch);
28 | System.out.println(ch+"\t"+Arrays.toString(arr_py));
29 | }
30 | ```
31 |
32 | output:
33 | ```
34 | 长 [chang, zhang]
35 | 行 [xing, hang, heng]
36 | 藏 [zang, cang]
37 | 度 [du, duo]
38 | 阿 [a, e]
39 | 佛 [fo, fu]
40 | 2 [2]
41 | A [A]
42 | a [a]
43 | ```
44 |
45 | ### 2. word
46 | ```
47 | Converter converter = new PinyinConverter();
48 |
49 | final String[] arr = {"肯德基", "重庆银行", "长沙银行", "便宜坊", "西藏", "藏宝图", "出差", "参加", "列车长"};
50 | for (String chinese : arr){
51 | String py = converter.getPinyin(chinese);
52 | System.out.println(chinese+"\t"+py);
53 | }
54 | ```
55 |
56 | output:
57 | ```
58 | 肯德基 KenDeJi
59 | 重庆银行 ChongQingYinHang
60 | 长沙银行 ChangShaYinHang
61 | 便宜坊 BianYiFang
62 | 西藏 XiZang
63 | 藏宝图 CangBaoTu
64 | 出差 ChuChai
65 | 参加 CanJia
66 | 列车长 LieCheZhang
67 | ```
68 |
69 | ### 3.Extension vocabulary
70 | Create a file named **py4j.txt** in your project's classpath **META-INF/vocabulary** directory.
71 |
72 | Just like this:
73 | 
74 |
75 |
76 | **py4j.txt** Content format:
77 | ```
78 | bian#扁/便/便宜坊
79 | du#读/都/度
80 |
81 | ```
82 |
83 | ## Performance Tips
84 | > Py4j instances are Thread-safe so you can reuse them freely across multiple threads.
85 |
86 | Testcase:
87 | ```
88 | final String[] arr = {"大夫", "重庆银行", "长沙银行", "便宜坊", "西藏", "藏宝图", "出差", "参加", "列车长"};
89 | final Converter converter = new PinyinConverter();
90 |
91 | int threadNum = 20;
92 | ExecutorService pool = Executors.newFixedThreadPool(threadNum);
93 | for(int i=0;i() {
95 | @Override
96 | public Void call() throws Exception {
97 |
98 | System.out.println("thread "+Thread.currentThread().getName()+" start");
99 | for(int i=0;i<1000;i++){
100 | converter.getPinyin(arr[i%arr.length]);
101 | }
102 | System.out.println("thread "+Thread.currentThread().getName()+" over");
103 | return null;
104 | }
105 | });
106 | }
107 |
108 | pool.shutdown();
109 | ```
110 |
--------------------------------------------------------------------------------
/docs/wiki/Home.md:
--------------------------------------------------------------------------------
1 | # Home
--------------------------------------------------------------------------------
/docs/wiki/media/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/py4j/5b23bfd3e2170e969c0b8eca744011b6c02aa8ad/docs/wiki/media/1.png
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | com.mindflow
6 | py4j
7 | 1.0.0
8 | jar
9 |
10 | py4j
11 | http://maven.apache.org
12 |
13 |
14 | 1.7
15 | UTF-8
16 |
17 |
18 |
19 |
20 | com.belerweb
21 | pinyin4j
22 | 2.5.0
23 |
24 |
25 |
26 | com.google.guava
27 | guava
28 | 18.0
29 |
30 |
31 |
32 |
33 | org.slf4j
34 | slf4j-api
35 | 1.7.21
36 |
37 |
38 |
39 | junit
40 | junit
41 | 4.12
42 | test
43 |
44 |
45 |
46 |
47 |
48 |
49 | org.apache.maven.plugins
50 | maven-compiler-plugin
51 | 3.5.1
52 |
53 | ${java.version}
54 | ${java.version}
55 | ${java.version}
56 | ${java.version}
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/src/main/java/com/mindflow/py4j/Converter.java:
--------------------------------------------------------------------------------
1 | package com.mindflow.py4j;
2 |
3 | import com.mindflow.py4j.exception.IllegalPinyinException;
4 |
5 | /**
6 | * @author Ricky Fung
7 | */
8 | public interface Converter {
9 |
10 | String[] getPinyin(char ch) throws IllegalPinyinException;
11 |
12 | String getPinyin(String chinese) throws IllegalPinyinException;
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/mindflow/py4j/PinyinConverter.java:
--------------------------------------------------------------------------------
1 | package com.mindflow.py4j;
2 |
3 | import com.mindflow.py4j.exception.IllegalPinyinException;
4 | import com.mindflow.py4j.util.ArrayUtils;
5 | import com.mindflow.py4j.util.StringUtils;
6 | import com.google.common.collect.ArrayListMultimap;
7 | import com.mindflow.py4j.voc.Py4jDictionary;
8 | import net.sourceforge.pinyin4j.PinyinHelper;
9 | import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
10 | import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
11 | import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
12 | import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
13 | import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
14 |
15 | /**
16 | *
17 | * @author Ricky Fung
18 | */
19 | public class PinyinConverter implements Converter {
20 | private final ArrayListMultimap duoYinZiMap;
21 | public PinyinConverter(){
22 | this.duoYinZiMap = Py4jDictionary.getDefault().getDuoYinZiMap();
23 | }
24 |
25 | @Override
26 | public String[] getPinyin(char ch) throws IllegalPinyinException {
27 | try{
28 | HanyuPinyinOutputFormat outputFormat = new HanyuPinyinOutputFormat();
29 | outputFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
30 | outputFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
31 | outputFormat.setVCharType(HanyuPinyinVCharType.WITH_V);
32 |
33 | if(ch>=32 && ch<=125){ //ASCII >=33 ASCII<=125的直接返回 ,ASCII码表:http://www.asciitable.com/
34 | return new String[]{String.valueOf(ch)};
35 | }
36 | return ArrayUtils.distinct(PinyinHelper.toHanyuPinyinStringArray(ch, outputFormat));
37 | } catch (BadHanyuPinyinOutputFormatCombination e) {
38 | throw new IllegalPinyinException(e);
39 | }
40 |
41 | }
42 |
43 | @Override
44 | public String getPinyin(String chinese) throws IllegalPinyinException {
45 | if(StringUtils.isEmpty(chinese)){
46 | return null;
47 | }
48 |
49 | chinese = chinese.replaceAll("[\\.,\\,!·\\!?\\?;\\;\\(\\)()\\[\\]\\:: ]+", " ").trim();
50 |
51 | StringBuilder py_sb = new StringBuilder(32);
52 | char[] chs = chinese.toCharArray();
53 | for(int i=0;i=1 && i+1<=chinese.length()){
67 | left = chinese.substring(i-1,i+1);
68 | if(duoYinZiMap.containsKey(py) && duoYinZiMap.get(py).contains(left)){
69 | resultPy = py;
70 | break;
71 | }
72 | }
73 |
74 | String right = null; //向右多取一个字,例如 [长]沙
75 | if(i<=chinese.length()-2){
76 | right = chinese.substring(i,i+2);
77 | if(duoYinZiMap.containsKey(py) && duoYinZiMap.get(py).contains(right)){
78 | resultPy = py;
79 | break;
80 | }
81 | }
82 |
83 | String middle = null; //左右各多取一个字,例如 龙[爪]槐
84 | if(i>=1 && i+2<=chinese.length()){
85 | middle = chinese.substring(i-1,i+2);
86 | if(duoYinZiMap.containsKey(py) && duoYinZiMap.get(py).contains(middle)){
87 | resultPy = py;
88 | break;
89 | }
90 | }
91 | String left3 = null; //向左多取2个字,如 芈月[传],列车长
92 | if(i>=2 && i+1<=chinese.length()){
93 | left3 = chinese.substring(i-2,i+1);
94 | if(duoYinZiMap.containsKey(py) && duoYinZiMap.get(py).contains(left3)){
95 | resultPy = py;
96 | break;
97 | }
98 | }
99 |
100 | String right3 = null; //向右多取2个字,如 [长]孙无忌
101 | if(i<=chinese.length()-3){
102 | right3 = chinese.substring(i,i+3);
103 | if(duoYinZiMap.containsKey(py) && duoYinZiMap.get(py).contains(right3)){
104 | resultPy = py;
105 | break;
106 | }
107 | }
108 |
109 | if(duoYinZiMap.containsKey(py) && duoYinZiMap.get(py).contains(String.valueOf(chs[i]))){ //默认拼音
110 | defaultPy = py;
111 | }
112 | }
113 |
114 | if(StringUtils.isEmpty(resultPy)){
115 | if(StringUtils.isNotEmpty(defaultPy)){
116 | resultPy = defaultPy;
117 | }else{
118 | resultPy = py_arr[0];
119 | }
120 | }
121 | py_sb.append(convertInitialToUpperCase(resultPy));
122 | }
123 | }
124 |
125 | return py_sb.toString();
126 | }
127 |
128 | private String convertInitialToUpperCase(String str) {
129 | if (str == null || str.length()==0) {
130 | return "";
131 | }
132 | return str.substring(0, 1).toUpperCase()+str.substring(1);
133 | }
134 | }
135 |
136 |
--------------------------------------------------------------------------------
/src/main/java/com/mindflow/py4j/exception/IllegalPinyinException.java:
--------------------------------------------------------------------------------
1 | package com.mindflow.py4j.exception;
2 |
3 | /**
4 | *
5 | * @author Ricky Fung
6 | */
7 | public class IllegalPinyinException extends Exception {
8 |
9 | private static final long serialVersionUID = 4447260855879734366L;
10 |
11 | public IllegalPinyinException() {
12 | }
13 |
14 | public IllegalPinyinException(String message) {
15 | super(message);
16 | }
17 |
18 | public IllegalPinyinException(String message, Throwable cause) {
19 | super(message, cause);
20 | }
21 |
22 | public IllegalPinyinException(Throwable cause) {
23 | super(cause);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/mindflow/py4j/util/ArrayUtils.java:
--------------------------------------------------------------------------------
1 | package com.mindflow.py4j.util;
2 |
3 | import java.util.HashSet;
4 |
5 | /**
6 | * @author Ricky Fung
7 | */
8 | public class ArrayUtils {
9 |
10 | private ArrayUtils() {}
11 |
12 | public static String[] distinct(String[] arr) {
13 | if(arr==null || arr.length==0) {
14 | return arr;
15 | }
16 | HashSet set = new HashSet<>();
17 | for (String str : arr) {
18 | set.add(str);
19 | }
20 | return set.toArray(new String[0]);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/mindflow/py4j/util/IoUtils.java:
--------------------------------------------------------------------------------
1 | package com.mindflow.py4j.util;
2 |
3 | import java.io.Closeable;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.io.OutputStream;
7 |
8 | /**
9 | *
10 | * @author Ricky Fung
11 | */
12 | public class IoUtils {
13 |
14 | public static void closeQuietly(InputStream input){
15 | closeQuietly((Closeable)input);
16 | }
17 |
18 | public static void closeQuietly(OutputStream output){
19 | closeQuietly((Closeable)output);
20 | }
21 |
22 | public static void closeQuietly(Closeable closeable) {
23 | try {
24 | if(closeable != null) {
25 | closeable.close();
26 | }
27 | } catch (IOException e) {
28 | e.printStackTrace();
29 | }
30 | }
31 |
32 | public static void closeQuietly(Closeable... closeables){
33 | for (Closeable closeable : closeables){
34 | closeQuietly(closeable);
35 | }
36 | }
37 |
38 | public static long copy(InputStream in, OutputStream out, int bufferSize) throws IOException {
39 | byte[] buff = new byte[bufferSize];
40 | return copy(in, out, buff);
41 | }
42 |
43 | public static long copy(InputStream in, OutputStream out) throws IOException {
44 | byte[] buff = new byte[1024];
45 | return copy(in, out, buff);
46 | }
47 |
48 | public static long copy(InputStream in, OutputStream out, byte[] buff) throws IOException {
49 | long count = 0;
50 | int len = -1;
51 | while((len=in.read(buff, 0, buff.length))!=-1){
52 | out.write(buff, 0, len);
53 | count += len;
54 | }
55 | return count;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/mindflow/py4j/util/StringUtils.java:
--------------------------------------------------------------------------------
1 | package com.mindflow.py4j.util;
2 |
3 | /**
4 | * ${DESCRIPTION}
5 | *
6 | * @author Ricky Fung
7 | */
8 | public class StringUtils {
9 |
10 | public static final String EMPTY = "";
11 |
12 | public static boolean isEmpty(final CharSequence cs) {
13 | return cs == null || cs.length() == 0;
14 | }
15 |
16 | public static boolean isNotEmpty(final CharSequence str) {
17 | return !isEmpty(str);
18 | }
19 |
20 | public static boolean isBlank(final CharSequence cs) {
21 | int strLen;
22 | if (cs == null || (strLen = cs.length()) == 0) {
23 | return true;
24 | }
25 | for (int i = 0; i < strLen; i++) {
26 | if (Character.isWhitespace(cs.charAt(i)) == false) {
27 | return false;
28 | }
29 | }
30 | return true;
31 | }
32 |
33 | public static boolean isNotBlank(final CharSequence cs) {
34 | return !isBlank(cs);
35 | }
36 |
37 | public static boolean equals(String str1, String str2) {
38 | return str1 == null?str2 == null:str1.equals(str2);
39 | }
40 |
41 | public static boolean equalsIgnoreCase(String str1, String str2) {
42 | return str1 == null?str2 == null:str1.equalsIgnoreCase(str2);
43 | }
44 |
45 | public static boolean contains(String[] arr, String searchStr) {
46 | if (arr == null || searchStr == null) {
47 | return false;
48 | }
49 | for(String str : arr) {
50 | if(searchStr.equals(str)){
51 | return true;
52 | }
53 | }
54 | return false;
55 | }
56 |
57 | /**
58 | * StringUtils.capitalize(null) = null
59 | * StringUtils.capitalize("") = ""
60 | * StringUtils.capitalize("cat") = "Cat"
61 | * StringUtils.capitalize("cAt") = "CAt"
62 | * StringUtils.capitalize("'cat'") = "'cat'"
63 | *
64 | * @param str
65 | * @return
66 | */
67 | public static String capitalize(final String str) {
68 | int strLen;
69 | if (str == null || (strLen = str.length()) == 0) {
70 | return str;
71 | }
72 |
73 | final char firstChar = str.charAt(0);
74 | final char newChar = Character.toTitleCase(firstChar);
75 | if (firstChar == newChar) {
76 | // already capitalized
77 | return str;
78 | }
79 |
80 | char[] newChars = new char[strLen];
81 | newChars[0] = newChar;
82 | str.getChars(1,strLen, newChars, 1);
83 | return String.valueOf(newChars);
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/main/java/com/mindflow/py4j/voc/Py4jDictionary.java:
--------------------------------------------------------------------------------
1 | package com.mindflow.py4j.voc;
2 |
3 | import com.mindflow.py4j.util.IoUtils;
4 | import com.mindflow.py4j.util.StringUtils;
5 | import com.google.common.collect.ArrayListMultimap;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import java.io.BufferedReader;
10 | import java.io.IOException;
11 | import java.io.InputStream;
12 | import java.io.InputStreamReader;
13 | import java.net.URL;
14 | import java.util.Enumeration;
15 |
16 | /**
17 | *
18 | * @author Ricky Fung
19 | */
20 | public class Py4jDictionary {
21 | private final Logger logger = LoggerFactory.getLogger(this.getClass());
22 |
23 | private static final String PREFIX = "META-INF/vocabulary/";
24 |
25 | private ArrayListMultimap duoYinZiMap;
26 |
27 | private static final String CONFIG_NAME = "py4j.txt";
28 |
29 | private static final String PINYIN_SEPARATOR = "#";
30 |
31 | private static final String WORD_SEPARATOR = "/";
32 |
33 | private volatile boolean initialized;
34 |
35 | public Py4jDictionary(){
36 |
37 | }
38 |
39 | public static Py4jDictionary getDefault(){
40 | return SingletonHolder.INSTANCE;
41 | }
42 |
43 | public ArrayListMultimap getDuoYinZiMap(){
44 | checkInit();
45 | return duoYinZiMap;
46 | }
47 |
48 | private void checkInit() {
49 | if (!initialized) {
50 | loadVocabulary();
51 | }
52 | }
53 |
54 | private synchronized void loadVocabulary() {
55 | if(initialized){
56 | return;
57 | }
58 | this.duoYinZiMap = loadVocabulary0(CONFIG_NAME);
59 | initialized = true;
60 | }
61 |
62 | private ArrayListMultimap loadVocabulary0(String name) {
63 | debug("******start load py4j config******");
64 | ArrayListMultimap duoYinZiMap = ArrayListMultimap.create(512, 32);
65 | String filename = PREFIX + name;
66 | try{
67 | ClassLoader cl = Thread.currentThread().getContextClassLoader();
68 | Enumeration urls = cl.getResources(filename);
69 | if(urls!=null){
70 | while (urls.hasMoreElements()) {
71 | URL url = urls.nextElement();
72 | parseURL(url, duoYinZiMap);
73 | }
74 | }
75 | } catch (Exception e){
76 | error("caught exception when load py4j vocabulary", e);
77 | throw new RuntimeException("caught exception when load py4j vocabulary", e);
78 | }
79 | debug("******load py4j config over******");
80 | debug("py4j map key size:{}", duoYinZiMap.keySet().size());
81 | return duoYinZiMap;
82 | }
83 |
84 | private void parseURL(URL url, ArrayListMultimap duoYinZiMap){
85 | debug("load py4j dictionary file:{}", url.getPath());
86 | InputStream in = null;
87 | BufferedReader br = null;
88 | try {
89 | in = url.openStream();
90 | br = new BufferedReader(new InputStreamReader(in, "UTF-8"));
91 | String line = null;
92 | while ((line = br.readLine()) != null) {
93 |
94 | String[] arr = line.split(PINYIN_SEPARATOR);
95 |
96 | if (StringUtils.isNotEmpty(arr[1])) {
97 | String[] dyzs = arr[1].split(WORD_SEPARATOR);
98 | for (String dyz : dyzs) {
99 | if (StringUtils.isNotEmpty(dyz)) {
100 | duoYinZiMap.put(arr[0], dyz.trim());
101 | }
102 | }
103 | }
104 | }
105 | } catch (IOException e) {
106 | throw new RuntimeException(String.format("load py4j config:%s error", url), e);
107 | } finally {
108 | IoUtils.closeQuietly(br);
109 | IoUtils.closeQuietly(in);
110 | }
111 | }
112 |
113 | private void error(String msg, Throwable err){
114 | logger.error(msg, err);
115 | }
116 |
117 | private void debug(String msg, Object... args) {
118 | if(logger.isDebugEnabled()) {
119 | logger.debug(msg, args);
120 | }
121 | }
122 |
123 | private static class SingletonHolder {
124 | private static final Py4jDictionary INSTANCE = new Py4jDictionary();
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/vocabulary/py4j.txt:
--------------------------------------------------------------------------------
1 | a#阿
2 | ao#拗口/违拗/拗断/执拗/拗口/拗口风/拗口令/拗曲/拗性/拗折/警拗
3 | ai#艾
4 | bang#膀/磅/蚌
5 | ba#扒
6 | bai#叔伯/百/柏杨/㧳/梵呗/呗佛/呗音/呗唱/呗偈/呗声/呗赞/赞呗
7 | bao#剥皮/薄/暴/堡/曝
8 | bei#呗
9 | beng#蚌埠
10 | bi#复辟/臂/秘鲁/泌阳
11 | bing#屏息/屏弃/屏气/屏除/屏声
12 | bian#扁/便/便宜坊
13 | bo#薄荷/单薄/伯/泊/波/柏/萝卜/孛
14 | bu#卜/柨
15 | can#参
16 | cang#藏/欌
17 | cen#参差
18 | ceng#曾/噌
19 | cha#差/刹那/宝刹/一刹/查/碴/喳喳/喀喳
20 | chai#公差/差役/专差/官差/听差/美差/办差/差事/差使/肥差/当差/钦差/苦差/出差
21 | chan#颤/单于/禅
22 | chang#长/厂
23 | chao#朝/嘲/焯
24 | che#工尺/车
25 | chen#称职/匀称/称心/相称/对称
26 | cheng#称/乘/澄/噌吰/橙 秤/盛满/盛器/盛饭
27 | chu#畜
28 | chui#椎心
29 | chuai#揣
30 | chuan#传
31 | chi#匙/尺/吃
32 | chong#重庆/重重/虫
33 | chou#臭/帱
34 | chuang#经幢
35 | chuo#绰
36 | ci#参差/鳞差/伺候/龟兹
37 | cuan#攒聚/攒动/攒集/攒宫/攒所
38 | cuo#撮儿/撮要/撮合
39 | da#大/嗒
40 | dao#叨/帱载/帱察
41 | dai#大夫
42 | dan#单/弹/掸/澹
43 | dang#铛
44 | de#的/得
45 | di#堤/底/怎的/有的/目的/标的/打的/的确/有的放/的卢/矢之的/言中的/语中的/的士/地/提防/快的/美的
46 | diao#蓝调/调调/音调/论调/格调/调令/低调/笔调/基调/强调/声调/滥调/老调/色调/单调/腔调/跑调/曲调/步调/语调/主调/情调
47 | ding#丁
48 | du#读/都/度
49 | dou#全都/句读
50 | duo#舵/测度/忖度/揣度/猜度
51 | dun#粮囤/盾/顿/沌/敦
52 | e#阿谀/阿胶/阿弥/恶/擜
53 | er#儿
54 | fan#番
55 | feng#冯
56 | fei#婔
57 | fo#佛
58 | fu#仿佛/果脯/罘/莩
59 | fou#否
60 | fiao#覅
61 | ga#咖喱/伽马/嘎/戛纳
62 | gai#盖
63 | gao#告
64 | gang#扛鼎
65 | ge#革/蛤蚧/文蛤/蛤蜊/咯
66 | gei#给
67 | geng#脖颈
68 | gong#女红/共
69 | gu#谷/中鹄/鼓
70 | gui#龟/柜/硅/倭傀/傀异/傀然/傀垒/傀怪/傀卓/傀奇/傀伟/傀民/傀俄/琦傀/奇傀
71 | gua#呱
72 | guan#纶巾/东莞
73 | guang#广
74 | ha#蛤/哈/虾蟆
75 | hai#还/嗨/咳声/咳笑
76 | hao#貉子/貉绒
77 | hang#夯/总行/分行/支行/行业/排行/行情/央行/商行/外行/银行/中行/交行/招行/农行/工行/建行/商行/酒行/麻行/琴行/行业/同行/行列/行货/行会/行家/巷道/引吭/扼吭/批吭/搤吭/高吭/喉吭/咔吭/絶吭/吭嗌/吭咽/吭首
78 | he#和/合/核/鶴/猲
79 | heng#道行/涥
80 | hu#鹄/水浒/嗀/唬
81 | hua#滑/呚/椛
82 | huan#归还/放还/奉还/圜
83 | hui#会/浍河/媈/灳/哕/瑗珲
84 | hong#红/虹
85 | huo#软和/热和/暖和
86 | hun#尡/珲
87 | ji#病革/给养/自给/给水/薪给/给予/供给/稽/缉/藉/奇数/亟/诘屈/荠菜/愱
88 | jia#雪茄/伽/家/价/贾/戛
89 | jian#见/浅浅
90 | jiang#降
91 | jiao#嚼舌/嚼字/嚼蜡/角/剿/饺/脚/蕉/矫/睡觉/侥/校对/校验/校正/校准/审校/校场/校核/校勘/校订/校阅/校样
92 | jie#解/慰藉/蕴藉/诘/媘/煯
93 | jin#矜/劲/禁
94 | jing#颈/景/强劲/劲风/劲旅/劲敌/劲射/苍劲/遒劲/劲草
95 | jiong#炅
96 | ju#咀/居/桔/句/婮
97 | jun#均
98 | juan#棚圈/圈养/猪圈/羊圈
99 | jue#主角/角色/旦角/女角/丑角/角力/名角/配角/嚼/觉/䏐
100 | jun#龟裂/俊
101 | ka#咖/卡/喀
102 | kai#楷
103 | kang#扛
104 | ke#咳/壳
105 | keng#吭
106 | kuai#会计/财会/浍
107 | kui#傀
108 | kuo#括
109 | la#癞痢/腊/蜡
110 | lai#癞疮/癞子/癞蛤/癞皮
111 | lao#积潦/络子/落枕/落价/粩/姥
112 | le#乐/勒/了
113 | lei#勒紧
114 | lo#然咯
115 | lou#佝偻/泄露/露面/露脸/露骨/露底/露馅/露一手/露相/露马脚/露怯
116 | long#里弄/弄堂/泷
117 | li#跞/礼/櫔/栃
118 | liao#了解/了结/明了/了得/末了/未了/了如/潦/撩
119 | liang#靓/俩
120 | lie#挘
121 | lin#崊
122 | ling#霗/令
123 | liu#六/遛
124 | lu#碌/陆/露
125 | luo#络/落/漯/囖/洜/泺
126 | lv#率/绿
127 | lve#鋢/稤
128 | lun#纶
129 | ma#嫲/抹布/抹脸/抹桌子/摩挲
130 | mai#埋
131 | man#埋怨/蔓
132 | mai#脉
133 | mang#氓/芒
134 | mao#冒
135 | me#嚒
136 | men#椚
137 | meng#群氓/盟/癦
138 | mei#没/旀
139 | mo#淹没/没收/出没/沉没/没落/吞没/覆没/没入/埋没/鬼没/隐没/湮没/辱没/脉脉/模/摩/抹
140 | mou#绸缪/牟
141 | mi#秘/泌尿/分泌/谜/檷枸
142 | mian#渑
143 | ming#掵
144 | miu#谬/谬论/纰缪
145 | mu#大模/字模/模板/模样/模具/装模/模子/牟尼/子牟/夷牟/悬牟/相牟/头牟/宾牟/曹牟/岑牟/兜牟/卢牟/弥牟/牟食/牟槊/牟衫/牟光/牟牟/牟甲
146 | na#哪/娜/那
147 | nao#臑
148 | nan#南
149 | ne#哪吒/呢
150 | nei#氞
151 | neus#莻
152 | nong#弄/燶
153 | ni#毛呢/花呢/呢绒/线呢/呢料/呢子/呢喃/溺/檷
154 | niao#尿/鸟/便溺
155 | nian#粘膜/粘度/粘土/粘合剂/粘液/粘稠/粘合/粘着/粘结/粘性/粘附/不粘锅/粘糊/粘虫/粘聚/粘滞/焾/哖
156 | niang#酿
157 | nin#脌
158 | ning#倿/拧
159 | niu#拗/汼
160 | nu#努
161 | nuo#婀娜/袅娜/喏
162 | nv#女
163 | nve#疟/硸
164 | o#喔/筽
165 | ou#膒
166 | pa#扒手/扒窃/扒外/扒分/扒糕/扒灰/扒犁/扒龙/扒搂/扒山虎/扒艇
167 | pai#派/迫击/迫击炮
168 | pao#刨/炮/萢
169 | pan#番禺
170 | pang#胖/膀/磅
171 | pei#蓜
172 | pi#辟/否极/臧否/龙陂/芘
173 | pian#扁舟/便宜/魸
174 | piao#朴姓/饿莩/饥莩/葭莩
175 | pin#穦
176 | ping#屏/苹/冯河
177 | po#湖泊/血泊 /迫/朴刀/坡/陂
178 | pu#一曝十寒/里堡/十里堡/脯/朴/曝晒/瀑/埔
179 | qi#期/其/泣/祇
180 | qiu#龟兹/湭
181 | qi#稽首/缉鞋/栖/奇/漆/齐
182 | qia#卡脖/卡子/关卡/卡壳/哨卡/边卡/发卡/峠
183 | qiao#雀盲/雀子/地壳/甲壳/躯壳
184 | qian#纤/乾/浅
185 | qiang#强/㛨/㩖/䅚/䵁
186 | qie#茄/趔趄/聺/籡
187 | qin#亲/沁
188 | qing#干亲/亲家
189 | qiong#熍
190 | qu#区/趣/爠
191 | quan#圈/券
192 | que#雀/炔
193 | re#声喏/唱喏
194 | rong#嬫
195 | ruo#若/嵶
196 | saeng#栍
197 | sang#槡
198 | sai#塞/嘥
199 | sao#螦
200 | se#堵塞/搪塞/茅塞/闭塞/鼻塞/梗塞/阻塞/淤塞/拥塞/哽塞/色
201 | sha#莎/刹车/急刹/厦/杉木/杉篙
202 | shai#色子
203 | shao#勺/红苕
204 | shan#姓单/单县/杉/敾/禅让/受禅/禅变/禅代/禅诰
205 | shang#衣裳
206 | she#拾级/折本/射/蛇
207 | shen#沙参/野参/参王/人参/红参/丹参/山参/海参/鹿参/什么/身/沈/桑椹/食椹/烂椹/木椹
208 | sheng#野乘/千乘/史乘/省/晟/盛/陹/渑水
209 | shi#钥匙/什/识/似的/食/石/氏/拾/适/瑡
210 | shiwa#瓧
211 | shuai#表率/率性/率直/率真/粗率/率领/轻率/直率/草率/大率/坦率/衰
212 | shuang#泷水/鏯
213 | shu#属/数/术/熟
214 | shui#游说
215 | shuo#数见/说
216 | si#伺/似/思
217 | sou#蓃/摗
218 | su#宿/鯂
219 | sui#尿泡
220 | ta#拓片/拓印/拓本/拓墨/拓写/拓手/拓工/碑拓/疲沓/拖沓/杂沓/沓/塔/鸿塔
221 | tang#汤/镗
222 | tao#陶
223 | tan#反弹/弹性/弹簧/弹力/弹奏/弹跳/弹指/弹劾/弹唱/弹射/弹性体/吹弹/评弹/乱弹琴/弹压/弹指/弹簧/弹冠/弹雀/弹雀/弹丝/弹丸/澹台
224 | te#脦
225 | teng#虅
226 | ti#提/体
227 | tiao#调/苕
228 | ting#町/听
229 | tong#通
230 | tu#迌
231 | tuan#湪
232 | tui#褪
233 | tuo#拓/袥
234 | tun#囤/屯
235 | wei#尾/蔚/圩堤/圩垸/圩田/圩子/赶圩/歌圩
236 | weng#攚
237 | wu#无/可恶/交恶/好恶/厌恶/憎恶/嫌恶/痛恶/深恶/兀
238 | wan#藤蔓/枝蔓/根蔓/蔓草/瓜蔓/蔓儿/莞/万/百万/皖
239 | wang#亡
240 | wai#崴
241 | xia#虾/吓/夏/厦门/厦大/唬杀
242 | xi#栖/系/蹊/洗/溪/戏/焁/铣/褶衣/褶裤
243 | xiao#校/切削/削面/刀削/刮削
244 | xian#纤细/光纤/纤巧/纤柔/纤小/纤维/纤瘦/纤纤/化纤/纤秀/棉纤/纤尘/铣铁/金铣
245 | xiang#投降/巷
246 | xie#解数/出血/采血/换血/血糊/尿血/淤血/放血/血晕/血淋/便血/吐血/咯血/叶韵/蝎/蝎子/邪/猲猲
247 | xin#嬜/邤
248 | xiu#铜臭/乳臭/成宿/星宿/璓
249 | xin#馨/信/鸿信
250 | xing#深省/省视/内省/不省人事/省悟/省察/行/荥
251 | xiong#匂
252 | xu#牧畜/畜产/畜牧/畜养/并畜/畜锐/吁/圩/浒
253 | xuan#箮
254 | xue#削/血/樰
255 | xun#荨/寻
256 | ya#琊
257 | yao#钥/耀/曜/佋侥/侥觎/侥僺/侥利/侥傒/侥觊/侥会/侥滥/侥望/侥求/侥竞/侥薄/侥躐/侥取/侥奇/侥忝/侥速/侥冀/侥冒/疟子
258 | yan#咽/殷红/朱殷/腌/烟/曕
259 | ye#液/抽咽/哽咽/咽炎/呜咽/幽咽/悲咽/叶/葉/璍/潱/拽步/拽扶/拽扎
260 | yi#自艾/遗/屹/嬄/噫
261 | yin#殷/栶
262 | ying#荥经/緓/灜
263 | yo#杭育
264 | yong#涌/硧
265 | you#牗
266 | yu#余/呼吁/吁请/吁求/育/熨帖/熨烫/於
267 | yuan#员/茒/圜丘
268 | yun#熨
269 | yue#约/乐音/器乐/乐律/乐章/音乐/乐理/民乐/乐队/声乐/奏乐/弦乐/乐坛/管乐/配乐/乐曲/乐谱/锁钥/密钥/乐团/乐器/嬳/咽哕/唾哕/发哕/干哕/哕吐/哕饭/哕呕/哕息/哕厥/哕噫/哕逆/哕咽/哕骂/哕心/哕喈/口哕/呕哕
270 | za#绑扎/结扎/包扎/捆扎/咱家
271 | zan#攒/咱
272 | zang#宝藏/藏历/藏文/藏语/藏青/藏族/藏医/藏药/藏蓝/西藏
273 | zai#牛仔/龟仔/龙仔/鼻仔/羊仔/仔仔/麻仔/麵包仔/麦旺仔/鸿仔/煲仔/福仔/畠
274 | zao#栆
275 | ze#择
276 | zeng#曾国藩/曾孙/曾祖父/曾祖/曾祖母/曾孙女/曾巩/囎/缯
277 | zong#综/繌
278 | zha#扎/柞狭/柞薪/柞子/柞鄂/柞叶/柞撒/槱柞/一柞/五柞宫/五柞/雠柞/芟柞/蜡祭/喳
279 | zhai#宅/夈/择席/择菜
280 | zhan#粘
281 | zhang#列车长/行长/村长/镇长/乡长/区长/县长/市长/省长/会长/班长/排长/连长/营长/团长/旅长/师长/军长/委员长/局长/厅长/所长/部长/组长/生长/长大/长高/长个/
282 | zhao#朝朝/明朝/朝晖/朝夕/朝思/今朝/朝气/朝三/朝秦/朝霞/鹰爪/龙爪/魔爪/爪牙/着急/着迷/着火/怎么着/正着/着凉/一着/犯不着/着数/这么着/犯得着/着慌/着忙/数得着/龙爪槐/嘲哳/嘲惹
283 | zhe#折/着/褶
284 | zhen#殝/椹
285 | zhi#标识/吱/殖/枝/方祇/后祇/皇祇/黄祇/皇地祇/金祇/祇树/月氏
286 | zhong#重/种
287 | zhou#粥
288 | zhu#属意/著/駯
289 | zhua#爪子
290 | zhuai#拽
291 | zhuan#芈月传/外传/传记/自传/正传/小传/评传/传略/别传
292 | zhui#椎/隹
293 | zhuo#执著/着装/着落/着意/着力/附着/着笔/胶着/着实/衣着/着眼/着想/着重/穿着/执着/着墨/着实/沉着/着陆/着想/着色/焯见/焯烁/辉焯
294 | zhuang#幢房/一幢/幢楼/庒
295 | zi#仔/兹
296 | zu#足
297 | zuo#柞/穝
298 |
--------------------------------------------------------------------------------
/src/test/java/com/mindflow/py4j/PinyinConverterTest.java:
--------------------------------------------------------------------------------
1 | package com.mindflow.py4j;
2 |
3 | import com.mindflow.py4j.exception.IllegalPinyinException;
4 | import org.junit.*;
5 |
6 | import java.util.Arrays;
7 |
8 | /**
9 | * Unit test for simple App.
10 | */
11 | public class PinyinConverterTest {
12 | private Converter converter;
13 |
14 | @Before
15 | public void init(){
16 | converter = new PinyinConverter();
17 | }
18 |
19 | @Test
20 | public void testChinesePy() throws IllegalPinyinException {
21 |
22 | final String[] arr = {"肯德基", "重庆银行", "长沙银行", "便宜坊", "西藏", "藏宝图", "出差", "参加", "列车长"};
23 |
24 | for (String chinese : arr){
25 | String py = converter.getPinyin(chinese);
26 | System.out.println(chinese+"\t"+py);
27 | }
28 | }
29 |
30 | @Test
31 | public void testCharPy() throws IllegalPinyinException {
32 |
33 | char[] chs = {'嗯', '长', '行', '藏', '度', '阿', '佛', '2', 'A', 'a'};
34 | for(char ch : chs){
35 | String[] arr_py = converter.getPinyin(ch);
36 | System.out.println(ch+"\t"+Arrays.toString(arr_py));
37 | }
38 | }
39 |
40 | @After
41 | public void destroy(){
42 | converter = null;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/com/mindflow/py4j/ThreadSafeTest.java:
--------------------------------------------------------------------------------
1 | package com.mindflow.py4j;
2 |
3 | import java.util.concurrent.Callable;
4 | import java.util.concurrent.ExecutorService;
5 | import java.util.concurrent.Executors;
6 |
7 | /**
8 | * ${DESCRIPTION}
9 | *
10 | * @author Ricky Fung
11 | * @create 2017-02-16 23:57
12 | */
13 | public class ThreadSafeTest {
14 |
15 | public static void main(String[] args) {
16 |
17 | final String[] arr = {"大夫", "重庆银行", "长沙银行", "便宜坊", "西藏", "藏宝图", "出差", "参加", "列车长"};
18 | final Converter converter = new PinyinConverter();
19 |
20 | int threadNum = 20;
21 | ExecutorService pool = Executors.newFixedThreadPool(threadNum);
22 | for(int i=0;i() {
24 | @Override
25 | public Void call() throws Exception {
26 |
27 | System.out.println("thread "+Thread.currentThread().getName()+" start");
28 | for(int i=0;i<1000;i++){
29 | converter.getPinyin(arr[i%arr.length]);
30 | }
31 | System.out.println("thread "+Thread.currentThread().getName()+" over");
32 | return null;
33 | }
34 | });
35 | }
36 |
37 | pool.shutdown();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------