// License & terms of use: http://www.unicode.org/copyright.html
// Generated using tools/cldr/cldr-to-icu/build-icu-data.xml
//
-// Remove Burmese and Thai dictionaries and replaced with lstm models.
+// Include Burmese and Thai lstm models.
{
"featureFilters": {
- "brkitr_dictionaries": {
- "excludelist": [
- "burmesedict",
- "thaidict"
- ]
- },
"brkitr_lstm": {
"includelist": [
"Thai_graphclust_model4_heavy",
[ -d icu4j/out/junit-results ] && cd icu4j && cat `find out/junit-results -name "*.txt" -exec grep -l FAILED {} \;`;
if: ${{ failure() }}
+ # ICU4J build and unit test under lstm
+ lstm-icu4j-build-and-test:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout and setup
+ uses: actions/checkout@v2
+ with:
+ lfs: true
+ - name: Checkout lfs objects
+ run: git lfs pull
+ - uses: actions/setup-java@v1
+ with:
+ java-version: '11'
+ - name: Config LSTM and Rebuild data jar
+ run: |
+ cd icu4c/source;
+ ICU_DATA_BUILDTOOL_OPTS=--include_uni_core_data ICU_DATA_FILTER_FILE=../../.github/lstm_for_th_my.json ./runConfigureICU --enable-debug --disable-release Linux -disable-layoutex;
+ make clean;
+ make -j2 ICU4J_ROOT=../../../icu4j icu4j-data-install;
+ cd ../..
+ - name: ICU4J
+ run: |
+ cd icu4j;
+ ant init;
+ ant check;
+ - name: List failures (if any)
+ run: |
+ [ -d icu4j/out/junit-results ] && cd icu4j && cat `find out/junit-results -name "*.txt" -exec grep -l FAILED {} \;`;
+ if: ${{ failure() }}
+
# gcc debug build.
# Includes dependency checker.
# Note - the dependency checker needs to be run on both a debug and an optimized build.
Thai:process(dependency){"thaidict.dict"}
}
lstm{
- Thai:process(dependency){"Thai_graphclust_model4_heavy.res"}
- Mymr:process(dependency){"Burmese_graphclust_model5_heavy.res"}
+ Thai{"Thai_graphclust_model4_heavy.res"}
+ Mymr{"Burmese_graphclust_model5_heavy.res"}
}
}
--- /dev/null
+// © 2021 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+//
+/**
+ * A LSTMBreakEngine
+ */
+package com.ibm.icu.impl.breakiter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.text.CharacterIterator;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.ibm.icu.impl.ICUData;
+import com.ibm.icu.impl.ICUResourceBundle;
+import com.ibm.icu.lang.UCharacter;
+import com.ibm.icu.lang.UProperty;
+import com.ibm.icu.lang.UScript;
+import com.ibm.icu.text.BreakIterator;
+import com.ibm.icu.text.UnicodeSet;
+import com.ibm.icu.util.UResourceBundle;
+
+/**
+ * @internal
+ */
+public class LSTMBreakEngine extends DictionaryBreakEngine {
+ public enum EmbeddingType {
+ UNKNOWN,
+ CODE_POINTS,
+ GRAPHEME_CLUSTER
+ }
+
+ public enum LSTMClass {
+ BEGIN,
+ INSIDE,
+ END,
+ SINGLE,
+ }
+
+ private static float[][] make2DArray(int[] data, int start, int d1, int d2) {
+ byte[] bytes = new byte[4];
+ float [][] result = new float[d1][d2];
+ for (int i = 0; i < d1 ; i++) {
+ for (int j = 0; j < d2 ; j++) {
+ int d = data[start++];
+ bytes[0] = (byte) (d >> 24);
+ bytes[1] = (byte) (d >> 16);
+ bytes[2] = (byte) (d >> 8);
+ bytes[3] = (byte) (d /*>> 0*/);
+ result[i][j] = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getFloat();
+ }
+ }
+ return result;
+ }
+
+ private static float[] make1DArray(int[] data, int start, int d1) {
+ byte[] bytes = new byte[4];
+ float [] result = new float[d1];
+ for (int i = 0; i < d1 ; i++) {
+ int d = data[start++];
+ bytes[0] = (byte) (d >> 24);
+ bytes[1] = (byte) (d >> 16);
+ bytes[2] = (byte) (d >> 8);
+ bytes[3] = (byte) (d /*>> 0*/);
+ result[i] = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getFloat();
+ }
+ return result;
+ }
+
+ /** @internal */
+ public static class LSTMData {
+ private LSTMData() {
+ }
+
+ public LSTMData(UResourceBundle rb) {
+ int embeddings = rb.get("embeddings").getInt();
+ int hunits = rb.get("hunits").getInt();
+ this.fType = EmbeddingType.UNKNOWN;
+ this.fName = rb.get("model").getString();
+ String typeString = rb.get("type").getString();
+ if (typeString.equals("codepoints")) {
+ this.fType = EmbeddingType.CODE_POINTS;
+ } else if (typeString.equals("graphclust")) {
+ this.fType = EmbeddingType.GRAPHEME_CLUSTER;
+ }
+ String[] dict = rb.get("dict").getStringArray();
+ int[] data = rb.get("data").getIntVector();
+ int dataLen = data.length;
+ int numIndex = dict.length;
+ fDict = new HashMap<String, Integer>(numIndex + 1);
+ int idx = 0;
+ for (String embedding : dict){
+ fDict.put(embedding, idx++);
+ }
+ int mat1Size = (numIndex + 1) * embeddings;
+ int mat2Size = embeddings * 4 * hunits;
+ int mat3Size = hunits * 4 * hunits;
+ int mat4Size = 4 * hunits;
+ int mat5Size = mat2Size;
+ int mat6Size = mat3Size;
+ int mat7Size = mat4Size;
+ int mat8Size = 2 * hunits * 4;
+ int mat9Size = 4;
+ assert dataLen == mat1Size + mat2Size + mat3Size + mat4Size + mat5Size + mat6Size + mat7Size + mat8Size + mat9Size;
+ int start = 0;
+ this.fEmbedding = make2DArray(data, start, (numIndex+1), embeddings);
+ start += mat1Size;
+ this.fForwardW = make2DArray(data, start, embeddings, 4 * hunits);
+ start += mat2Size;
+ this.fForwardU = make2DArray(data, start, hunits, 4 * hunits);
+ start += mat3Size;
+ this.fForwardB = make1DArray(data, start, 4 * hunits);
+ start += mat4Size;
+ this.fBackwardW = make2DArray(data, start, embeddings, 4 * hunits);
+ start += mat5Size;
+ this.fBackwardU = make2DArray(data, start, hunits, 4 * hunits);
+ start += mat6Size;
+ this.fBackwardB = make1DArray(data, start, 4 * hunits);
+ start += mat7Size;
+ this.fOutputW = make2DArray(data, start, 2 * hunits, 4);
+ start += mat8Size;
+ this.fOutputB = make1DArray(data, start, 4);
+ }
+
+ public EmbeddingType fType;
+ public String fName;
+ public Map<String, Integer> fDict;
+ public float fEmbedding[][];
+ public float fForwardW[][];
+ public float fForwardU[][];
+ public float fForwardB[];
+ public float fBackwardW[][];
+ public float fBackwardU[][];
+ public float fBackwardB[];
+ public float fOutputW[][];
+ public float fOutputB[];
+ }
+
+ // Minimum word size
+ private static final byte MIN_WORD = 2;
+
+ // Minimum number of characters for two words
+ private static final byte MIN_WORD_SPAN = MIN_WORD * 2;
+
+ abstract class Vectorizer {
+ public Vectorizer(Map<String, Integer> dict) {
+ this.fDict = dict;
+ }
+ abstract public void vectorize(CharacterIterator fIter, int rangeStart, int rangeEnd,
+ List<Integer> offsets, List<Integer> indicies);
+ protected int getIndex(String token) {
+ return fDict.getOrDefault(token, fDict.size());
+ }
+ private Map<String, Integer> fDict;
+ }
+
+ class CodePointsVectorizer extends Vectorizer {
+ public CodePointsVectorizer(Map<String, Integer> dict) {
+ super(dict);
+ }
+
+ public void vectorize(CharacterIterator fIter, int rangeStart, int rangeEnd,
+ List<Integer> offsets, List<Integer> indicies) {
+ fIter.setIndex(rangeStart);
+ for (char c = fIter.current();
+ c != CharacterIterator.DONE && fIter.getIndex() < rangeEnd;
+ c = fIter.next()) {
+ offsets.add(fIter.getIndex());
+ indicies.add(getIndex(String.valueOf(c)));
+ }
+ }
+ }
+
+ class GraphemeClusterVectorizer extends Vectorizer {
+ public GraphemeClusterVectorizer(Map<String, Integer> dict) {
+ super(dict);
+ }
+
+ private String substring(CharacterIterator text, int startPos, int endPos) {
+ int saved = text.getIndex();
+ text.setIndex(startPos);
+ StringBuilder sb = new StringBuilder();
+ for (char c = text.current();
+ c != CharacterIterator.DONE && text.getIndex() < endPos;
+ c = text.next()) {
+ sb.append(c);
+ }
+ text.setIndex(saved);
+ return sb.toString();
+ }
+
+ public void vectorize(CharacterIterator text, int startPos, int endPos,
+ List<Integer> offsets, List<Integer> indicies) {
+ BreakIterator iter = BreakIterator.getCharacterInstance();
+ iter.setText(text);
+ int last = iter.next(startPos);
+ for (int curr = iter.next(); curr != BreakIterator.DONE && curr <= endPos; curr = iter.next()) {
+ offsets.add(last);
+ String segment = substring(text, last, curr);
+ int index = getIndex(segment);
+ indicies.add(index);
+ last = curr;
+ }
+ }
+ }
+
+ private final LSTMData fData;
+ private int fScript;
+ private final Vectorizer fVectorizer;
+
+ private Vectorizer makeVectorizer(LSTMData data) {
+ switch(data.fType) {
+ case CODE_POINTS:
+ return new CodePointsVectorizer(data.fDict);
+ case GRAPHEME_CLUSTER:
+ return new GraphemeClusterVectorizer(data.fDict);
+ default:
+ return null;
+ }
+ }
+
+ public LSTMBreakEngine(int script, UnicodeSet set, LSTMData data) {
+ setCharacters(set);
+ this.fScript = script;
+ this.fData = data;
+ this.fVectorizer = makeVectorizer(this.fData);
+ }
+
+ @Override
+ public int hashCode() {
+ return getClass().hashCode();
+ }
+
+ @Override
+ public boolean handles(int c) {
+ return fScript == UCharacter.getIntPropertyValue(c, UProperty.SCRIPT);
+ }
+
+ static private void addDotProductTo(final float [] a, final float[][] b, float[] result) {
+ assert a.length == b.length;
+ assert b[0].length == result.length;
+ for (int i = 0; i < result.length; i++) {
+ for (int j = 0; j < a.length; j++) {
+ result[i] += a[j] * b[j][i];
+ }
+ }
+ }
+
+ static private void addTo(final float [] a, float[] result) {
+ assert a.length == result.length;
+ for (int i = 0; i < result.length; i++) {
+ result[i] += a[i];
+ }
+ }
+
+ static private void hadamardProductTo(final float [] a, float[] result) {
+ assert a.length == result.length;
+ for (int i = 0; i < result.length; i++) {
+ result[i] *= a[i];
+ }
+ }
+
+ static private void addHadamardProductTo(final float [] a, final float [] b, float[] result) {
+ assert a.length == result.length;
+ assert b.length == result.length;
+ for (int i = 0; i < result.length; i++) {
+ result[i] += a[i] * b[i];
+ }
+ }
+
+ static private void sigmoid(float [] result, int start, int length) {
+ assert start < result.length;
+ assert start + length <= result.length;
+ for (int i = start; i < start + length; i++) {
+ result[i] = (float)(1.0/(1.0 + Math.exp(-result[i])));
+ }
+ }
+
+ static private void tanh(float [] result, int start, int length) {
+ assert start < result.length;
+ assert start + length <= result.length;
+ for (int i = start; i < start + length; i++) {
+ result[i] = (float)Math.tanh(result[i]);
+ }
+ }
+
+ static private int maxIndex(float [] data) {
+ int index = 0;
+ float max = data[0];
+ for (int i = 1; i < data.length; i++) {
+ if (data[i] > max) {
+ max = data[i];
+ index = i;
+ }
+ }
+ return index;
+ }
+
+ /*
+ static private void print(float [] data) {
+ for (int i=0; i < data.length; i++) {
+ System.out.format(" %e", data[i]);
+ if (i % 4 == 3) {
+ System.out.println();
+ }
+ }
+ System.out.println();
+ }
+ */
+
+ private float[] compute(final float[][] W, final float[][] U, final float[] B,
+ final float[] x, float[] h, float[] c) {
+ // ifco = x * W + h * U + b
+ float[] ifco = Arrays.copyOf(B, B.length);
+ addDotProductTo(x, W, ifco);
+ float[] hU = new float[B.length];
+ addDotProductTo(h, U, ifco);
+
+ int hunits = B.length / 4;
+ sigmoid(ifco, 0*hunits, hunits); // i
+ sigmoid(ifco, 1*hunits, hunits); // f
+ tanh(ifco, 2*hunits, hunits); // c_
+ sigmoid(ifco, 3*hunits, hunits); // o
+
+ hadamardProductTo(Arrays.copyOfRange(ifco, hunits, 2*hunits), c);
+ addHadamardProductTo(Arrays.copyOf(ifco, hunits),
+ Arrays.copyOfRange(ifco, 2*hunits, 3*hunits), c);
+
+ h = Arrays.copyOf(c, c.length);
+ tanh(h, 0, h.length);
+ hadamardProductTo(Arrays.copyOfRange(ifco, 3*hunits, 4*hunits), h);
+ // System.out.println("c");
+ // print(c);
+ // System.out.println("h");
+ // print(h);
+ return h;
+ }
+
+ @Override
+ public int divideUpDictionaryRange(CharacterIterator fIter, int rangeStart, int rangeEnd,
+ DequeI foundBreaks) {
+ int beginSize = foundBreaks.size();
+
+ if ((rangeEnd - rangeStart) < MIN_WORD_SPAN) {
+ return 0; // Not enough characters for word
+ }
+ List<Integer> offsets = new ArrayList<Integer>(rangeEnd - rangeStart);
+ List<Integer> indicies = new ArrayList<Integer>(rangeEnd - rangeStart);
+
+ fVectorizer.vectorize(fIter, rangeStart, rangeEnd, offsets, indicies);
+
+ // To save the needed memory usage, the following is different from the
+ // Python or ICU4X implementation. We first perform the Backward LSTM
+ // and then merge the iteration of the forward LSTM and the output layer
+ // together because we only need to remember the h[t-1] for Forward LSTM.
+ int inputSeqLength = indicies.size();
+ int hunits = this.fData.fForwardU.length;
+ float c[] = new float[hunits];
+
+ // TODO: limit size of hBackward. If input_seq_len is too big, we could
+ // run out of memory.
+ // Backward LSTM
+ float hBackward[][] = new float[inputSeqLength][hunits];
+ for (int i = inputSeqLength - 1; i >= 0; i--) {
+ if (i != inputSeqLength - 1) {
+ hBackward[i] = Arrays.copyOf(hBackward[i+1], hunits);
+ }
+ // System.out.println("Backward LSTM " + i);
+ hBackward[i] = compute(this.fData.fBackwardW, this.fData.fBackwardU, this.fData.fBackwardB,
+ this.fData.fEmbedding[indicies.get(i)],
+ hBackward[i], c);
+ }
+
+ c = new float[hunits];
+ float forwardH[] = new float[hunits];
+ float both[] = new float[2*hunits];
+
+ // The following iteration merge the forward LSTM and the output layer
+ // together.
+ for (int i = 0 ; i < inputSeqLength; i++) {
+ // Forward LSTM
+ forwardH = compute(this.fData.fForwardW, this.fData.fForwardU, this.fData.fForwardB,
+ this.fData.fEmbedding[indicies.get(i)],
+ forwardH, c);
+
+ System.arraycopy(forwardH, 0, both, 0, hunits);
+ System.arraycopy(hBackward[i], 0, both, hunits, hunits);
+
+ //System.out.println("Merged " + i);
+ //print(both);
+
+ // Output layer
+ // logp = fbRow * fOutputW + fOutputB
+ float logp[] = Arrays.copyOf(this.fData.fOutputB, this.fData.fOutputB.length);
+ addDotProductTo(both, this.fData.fOutputW, logp);
+
+ int current = maxIndex(logp);
+
+ // BIES logic.
+ if (current == LSTMClass.BEGIN.ordinal() ||
+ current == LSTMClass.SINGLE.ordinal()) {
+ if (i != 0) {
+ foundBreaks.push(offsets.get(i));
+ }
+ }
+ }
+
+ return foundBreaks.size() - beginSize;
+ }
+
+ public static LSTMData createData(UResourceBundle bundle) {
+ return new LSTMData(bundle);
+ }
+
+ private static String defaultLSTM(int script) {
+ ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUData.ICU_BRKITR_BASE_NAME);
+ return rb.getStringWithFallback("lstm/" + UScript.getShortName(script));
+ }
+
+ public static LSTMData createData(int script) {
+ if (script != UScript.KHMER && script != UScript.LAO && script != UScript.MYANMAR && script != UScript.THAI) {
+ return null;
+ }
+ String name = defaultLSTM(script);
+ name = name.substring(0, name.indexOf("."));
+
+ UResourceBundle rb = UResourceBundle.getBundleInstance(
+ ICUData.ICU_BRKITR_BASE_NAME, name,
+ ICUResourceBundle.ICU_DATA_CLASS_LOADER);
+ return createData(rb);
+ }
+
+ public static LSTMBreakEngine create(int script, LSTMData data) {
+ String setExpr = "[[:" + UScript.getShortName(script) + ":]&[:LineBreak=SA:]]";
+ UnicodeSet set = new UnicodeSet();
+ set.applyPattern(setExpr);
+ set.compact();
+ return new LSTMBreakEngine(script, set, data);
+ }
+}
import java.text.CharacterIterator;
import java.util.ArrayList;
import java.util.List;
+import java.util.MissingResourceException;
import com.ibm.icu.impl.CharacterIteration;
import com.ibm.icu.impl.ICUBinary;
import com.ibm.icu.impl.breakiter.CjkBreakEngine;
import com.ibm.icu.impl.breakiter.DictionaryBreakEngine;
import com.ibm.icu.impl.breakiter.KhmerBreakEngine;
+import com.ibm.icu.impl.breakiter.LSTMBreakEngine;
import com.ibm.icu.impl.breakiter.LanguageBreakEngine;
import com.ibm.icu.impl.breakiter.LaoBreakEngine;
import com.ibm.icu.impl.breakiter.ThaiBreakEngine;
try {
switch (script) {
case UScript.THAI:
- eng = new ThaiBreakEngine();
+ try {
+ eng = LSTMBreakEngine.create(script, LSTMBreakEngine.createData(script));
+ } catch (MissingResourceException e) {
+ eng = new ThaiBreakEngine();
+ }
break;
case UScript.LAO:
eng = new LaoBreakEngine();
break;
case UScript.MYANMAR:
- eng = new BurmeseBreakEngine();
+ try {
+ eng = LSTMBreakEngine.create(script, LSTMBreakEngine.createData(script));
+ } catch (MissingResourceException e) {
+ eng = new BurmeseBreakEngine();
+ }
break;
case UScript.KHMER:
eng = new KhmerBreakEngine();
version https://git-lfs.github.com/spec/v1
-oid sha256:8f02ab2967eaf73b6d28c8340d70b20d5f194f6c0ac24fe8464b25fd56763b04
-size 13383786
+oid sha256:6614997945a564e6888da79d06283f519a34d9e13caf8b10eba68ee9f098efda
+size 13383850
version https://git-lfs.github.com/spec/v1
-oid sha256:26a032e0c9492cd986546eefb5ba54687598eb431caed531ccb00b12469421ca
-size 726547
+oid sha256:9184fdb3a90361165d9c90081a681450a6a049beaf669a24580dcf23134142c7
+size 825810
--- /dev/null
+# Copyright (C) 2021 and later: Unicode, Inc. and others.
+# License & terms of use: http://www.unicode.org/copyright.html
+Model: Burmese_graphclust_model5_heavy
+Embedding: grapheme_clusters_tf
+Input: အပြည်ပြည်ဆိုင်ရာလူ့အခွင့်အရေးကြေညာစာတမ်း
+Output: |အပြည်|ပြည်|ဆိုင်ရာ|လူ့|အခွင့်အရေး|ကြေညာစာတမ်း|
+Input: မျိုးရိုးဂုဏ်သိက္ခာနှင့်တကွ
+Output: |မျိုး|ရိုး|ဂုဏ်|သိက္ခာ|နှင့်|တ|ကွ|
--- /dev/null
+// © 2021 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+package com.ibm.icu.dev.test.rbbi;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+import java.util.Iterator;
+import java.util.stream.Stream;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import com.ibm.icu.dev.test.TestFmwk;
+import com.ibm.icu.impl.breakiter.DictionaryBreakEngine;
+import com.ibm.icu.impl.breakiter.LSTMBreakEngine;
+import com.ibm.icu.lang.UScript;
+import com.ibm.icu.util.UResourceBundle;
+
+/**
+ * LSTMBreakEngine data driven test.
+ * Perform the tests from the file *_Test.txt.
+ * The test data file is common to both ICU4C and ICU4J.
+ * See the data file for a description of the tests.
+ *
+ */
+@RunWith(JUnit4.class)
+public class LSTMBreakEngineTest extends TestFmwk {
+
+ private static final ClassLoader testLoader = LSTMBreakEngineTest.class.getClassLoader();
+
+ public LSTMBreakEngineTest() {
+ }
+
+ @Test
+ public void TestThaiGraphclust() {
+ runTestFromFile("Thai_graphclust_model4_heavy_Test.txt", UScript.THAI);
+ }
+
+ @Test
+ public void TestThaiCodepoints() {
+ runTestFromFile("Thai_codepoints_exclusive_model5_heavy_Test.txt", UScript.THAI);
+ }
+
+ @Test
+ public void TestBurmeseGraphclust() {
+ runTestFromFile("Burmese_graphclust_model5_heavy_Test.txt", UScript.MYANMAR);
+ }
+
+ private LSTMBreakEngine createEngineFromTestData(String modelName, int script) {
+ UResourceBundle bundle = UResourceBundle.getBundleInstance(
+ "com/ibm/icu/dev/data/testdata", modelName, testLoader);
+ return LSTMBreakEngine.create(script, LSTMBreakEngine.createData(bundle));
+ }
+
+ private void runTestFromFile(String filename, int script) {
+
+ String testString;
+ InputStream is = LSTMBreakEngineTest.class.getResourceAsStream("/com/ibm/icu/dev/test/rbbi/" + filename);
+ if (is == null) {
+ errln("Could not open test data file " + filename);
+ return;
+ }
+ Stream<String> lines = (new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))).lines();
+ Iterator<String> iterator = lines.iterator();
+ int caseNum = 0;
+ String expected = "";
+ String actual = "";
+ LSTMBreakEngine engine = null;
+ while (iterator.hasNext()) {
+ String line = iterator.next();
+ String fields[] = line.split("\t");
+ if (fields[0].equals("Model:")) {
+ engine = createEngineFromTestData(fields[1], script);
+ } else if (fields[0].equals("Input:")) {
+ caseNum++;
+ int length = fields[1].length();
+ CharacterIterator input = new StringCharacterIterator(fields[1]);
+ DictionaryBreakEngine.DequeI foundBreaks = new DictionaryBreakEngine.DequeI();
+ int ret = engine.findBreaks(input, 0, length, foundBreaks);
+ StringBuilder sb = new StringBuilder();
+ sb.append('{');
+ for (int i = 0; i < foundBreaks.size(); i++) {
+ sb.append(foundBreaks.elementAt(i)).append(", ");
+ }
+ sb.append(length).append('}');
+ actual = sb.toString();
+ } else if (fields[0].equals("Output:")) {
+ StringBuilder sb = new StringBuilder();
+ int sep;
+ int start = 0;
+ int curr = 0;
+ sb.append('{');
+ while ((sep = fields[1].indexOf('|', start)) >= 0) {
+ int len = sep - start;
+ if (len > 0) {
+ if (curr > 0) {
+ sb.append(", ");
+ }
+ curr += len;
+ sb.append(curr);
+ }
+ start = sep + 1;
+ }
+ sb.append('}');
+ expected = sb.toString();
+
+ assertEquals(line + " Test Case#" + caseNum , expected, actual);
+ }
+ }
+ }
+}
--- /dev/null
+// © 2021 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+package com.ibm.icu.dev.test.rbbi;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+import java.util.Iterator;
+import java.util.stream.Stream;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import com.ibm.icu.dev.test.TestFmwk;
+import com.ibm.icu.dev.test.TestUtil;
+import com.ibm.icu.impl.breakiter.LSTMBreakEngine;
+import com.ibm.icu.lang.UScript;
+import com.ibm.icu.text.BreakIterator;
+
+/**
+ * RBBILSTMTest data driven test.
+ * Perform the tests from the file *_Test.txt against the RBBI method
+ * under LSTM configuration. The test will not run if it is not under LSTM configuration.
+ * The test data file is common to both ICU4C and ICU4J.
+ * See the data file for a description of the tests.
+ */
+@RunWith(JUnit4.class)
+public class RBBILSTMTest extends TestFmwk {
+ public RBBILSTMTest() {
+ }
+
+ @Test
+ public void TestLSTMThai() {
+ runTestFromFile("Thai_graphclust_model4_heavy_Test.txt", UScript.THAI);
+ }
+
+ @Test
+ public void TestLSTMBurmese() {
+ runTestFromFile("Burmese_graphclust_model5_heavy_Test.txt", UScript.MYANMAR);
+ }
+
+ private void runTestFromFile(String filename, int script) {
+ // The expectation in this test depends on LSTM, skip the test if the
+ // configuration is not build with LSTM data.
+ org.junit.Assume.assumeTrue(!TestUtil.skipLSTMTest());
+
+ BreakIterator bi = BreakIterator.getWordInstance();
+ String testString;
+ InputStream is = RBBILSTMTest.class.getResourceAsStream("/com/ibm/icu/dev/test/rbbi/" + filename);
+ if (is == null) {
+ errln("Could not open test data file " + filename);
+ return;
+ }
+ Stream<String> lines = (new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))).lines();
+ Iterator<String> iterator = lines.iterator();
+ int caseNum = 0;
+ String expected = "";
+ String actual = "";
+ LSTMBreakEngine engine = null;
+ while (iterator.hasNext()) {
+ String line = iterator.next();
+ String fields[] = line.split("\t");
+ if (fields[0].equals("Model:")) {
+ String actualModelName = LSTMBreakEngine.createData(script).fName;
+ if (!actualModelName.equals(fields[1])) {
+ errln("The name of the built in model " + actualModelName +
+ " does not match the model (" + fields[1] + ") expected for this test");
+ return;
+ }
+ } else if (fields[0].equals("Input:")) {
+ caseNum++;
+ int length = fields[1].length();
+ String input = "prefix " + fields[1] + " suffix";
+ bi.setText(input);
+ System.out.println("Input = " + input);
+ StringBuilder sb = new StringBuilder();
+ sb.append('{');
+ for (int bp = bi.first(); bp != BreakIterator.DONE; bp = bi.next()) {
+ sb.append(bp);
+ if (bp != input.length()) {
+ sb.append(", ");
+ }
+ }
+ sb.append('}');
+ actual = sb.toString();
+ } else if (fields[0].equals("Output:")) {
+ StringBuilder sb = new StringBuilder();
+ int sep;
+ int start = 0;
+ int curr = 0;
+ sb.append("{0, ");
+ String input = "prefix| |" + fields[1] + "| |suffix";
+ while ((sep = input.indexOf('|', start)) >= 0) {
+ int len = sep - start;
+ if (len > 0) {
+ if (curr > 0) {
+ sb.append(", ");
+ }
+ curr += len;
+ sb.append(curr);
+ }
+ start = sep + 1;
+ }
+ sb.append(", ").append(curr + input.length() - start);
+ sb.append('}');
+ expected = sb.toString();
+
+ assertEquals(input + " Test Case#" + caseNum , expected, actual);
+ actual = "";
+ }
+ }
+ }
+}
import org.junit.runners.JUnit4;
import com.ibm.icu.dev.test.TestFmwk;
+import com.ibm.icu.dev.test.TestUtil;
import com.ibm.icu.impl.RBBIDataWrapper;
import com.ibm.icu.text.BreakIterator;
import com.ibm.icu.text.RuleBasedBreakIterator;
@Test
public void TestThaiDictionaryBreakIterator() {
+ // The expectations in this test heavily depends on the Thai dictionary.
+ // Therefore, we skip this test under the LSTM configuration.
+ org.junit.Assume.assumeTrue(!TestUtil.skipDictionaryTest());
int position;
int index;
int result[] = { 1, 2, 5, 10, 11, 12, 11, 10, 5, 2, 1, 0 };
import org.junit.runners.JUnit4;
import com.ibm.icu.dev.test.TestFmwk;
+import com.ibm.icu.dev.test.TestUtil;
import com.ibm.icu.impl.Utility;
import com.ibm.icu.lang.UCharacter;
import com.ibm.icu.text.BreakIterator;
@Test
public void TestExtended() {
+ // The expectations in this test heavily depends on the Thai dictionary.
+ // Therefore, we skip this test under the LSTM configuration.
+ org.junit.Assume.assumeTrue(!TestUtil.skipDictionaryTest());
TestParams tp = new TestParams();
--- /dev/null
+# Copyright (C) 2020 and later: Unicode, Inc. and others.
+# License & terms of use: http://www.unicode.org/copyright.html
+Note: model Thai_codepoints_exclusive_model5_heavy has been trained using an exclusive data set. However, if you like you can still test it by other types of data sets (not recommended).
+Model: Thai_codepoints_exclusive_model5_heavy
+Embedding: codepoints
+Input: ปฏิญญาสากลว่าด้วยสิทธิมนุษยชน
+Output: |ปฏิญญา|สากลว่า|ด้วย|สิทธิ|มนุษย|ชน|
+Input: คำปรารภ
+Output: |คำ|ปรารภ|
+Input: โดยที่การยอมรับนับถือเกียรติศักดิ์ประจำตัว
+Output: |โดย|ที่|การ|ยอม|รับ|นับ|ถือ|เกียรติศักดิ์|ประจำ|ตัว|
+Input: และสิทธิเท่าเทียมกันและโอนมิได้ของบรรดา
+Output: |และ|สิทธิ|เท่า|เทียม|กัน|และ|โอน|มิ|ได้|ของ|บรรดา|
+Input: สมาชิก
+Output: |สมา|ชิก|
+Input: ทั้ง
+Output: |ทั้ง|
+Input: หลายแห่งครอบครัว
+Output: |หลาย|แห่ง|ครอบครัว|
+Input: มนุษย์เป็นหลักมูลเหตุแห่งอิสรภาพ
+Output: |มนุษย์|เป็น|หลักมูล|เหตุ|แห่ง|อิสรภาพ|
+Input: ความยุติธรรม
+Output: |ความ|ยุติ|ธรรม|
+Input: และสันติภาพในโลก
+Output: |และ|สันติภาพ|ใน|โลก|
+Input: โดยที่การไม่นำพาและการเหยียดหยามต่อสิทธิมนุษยชน
+Output: |โดย|ที่|การ|ไม่|นำ|พา|และ|การ|เหยียด|หยาม|ต่อ|สิทธิ|มนุษยชน|
+Input: ยังผลให้มีการหระทำอันป่าเถื่อน
+Output: |ยัง|ผล|ให้|มี|การ|หระทำ|อัน|ป่า|เถื่อ|น|
+Input: ซี่งเป็นการละเมิดมโนธรรมของมนุษยชาติอย่างร้ายแรง
+Output: |ซี่ง|เป็น|การ|ละเมิดมโนธรรม|ของ|มนุษยชาติ|อย่าง|ร้าย|แรง|
+Input: และใต้
+Output: |และ|ใต้|
+Input: ได้
+Output: |ได้|
+Input: มีการประกาศว่า
+Output: |มี|การ|ประกาศ|ว่า|
+Input: ปณิธานสูงสุดของสามัญชนได้แก่ความต้องการให้มนุษย์มีชีวิตอยู่ในโลกด้วยอิสรภาพในการพูด
+Output: |ปณิธาน|สูงสุด|ของ|สามัญชน|ได้|แก่|ความ|ต้องการ|ให้|มนุษย์|มี|ชีวิต|อยู่|ใน|โลก|ด้วย|อิสรภาพ|ใน|การ|พูด|
+Input: และความเชื่อถือ
+Output: |และ|ความ|เชื่อถือ|
+Input: และอิสรภาพพ้นจากความหวาดกลัวและความต้องการ
+Output: |และ|อิสรภาพ|พ้น|จาก|ความ|หวาด|กลัว|และ|ความ|ต้องการ|
+Input: โดยที่เป็นการจำเป็นอย่างยิ่งที่สิทธิมนุษยชนควรได้รับความคุ้มครองโดยหลักบังคับของกฎหมาย
+Output: |โดย|ที่|เป็น|การ|จำเป็น|อย่าง|ยิ่ง|ที่|สิทธิ|มนุษยชน|ควร|ได้|รับ|ความ|คุ้มครอง|โดย|หลัก|บังคับ|ของ|กฎหมาย|
+Input: ถ้าไม่ประสงค์จะให้คนตกอยู่ในบังคับให้หันเข้าหาการขบถขัดขืนต่อทรราชและการกดขี่เป็นวิถีทางสุดท้าย
+Output: |ถ้า|ไม่|ประสงค์|จะ|ให้|คน|ตก|อยู่|ใน|บังคับ|ให้|หัน|เข้า|หา|การ|ขบถ|ขัด|ขืน|ต่อทรราช|และ|การ|กด|ขี่|เป็น|วิถี|ทาง|สุด|ท้าย|
+Input: โดยที่ประชากรแห่งสหประชาชาติได้ยืนยันไว้ในกฎบัตรถึงความเชื่อมั่นในสิทธิมนุษยชนอันเป็นหลักมูล
+Output: |โดย|ที่|ประชากร|แห่ง|สหประชา|ชาติ|ได้|ยืน|ยัน|ไว้|ใน|กฎบัตร|ถึง|ความ|เชื่อมั่น|ใน|สิทธิ|มนุษยชน|อัน|เป็น|หลัก|มู|ล|
+Input: ในเกียรติศักดิ์และคุณค่าของมนุษย์และในสิทธิเท่าเทียมกันของบรรดาชายและหญิง
+Output: |ใน|เกียรติศักดิ์|และ|คุณค่า|ของ|มนุษย์|และ|ใน|สิทธิ|เท่า|เทียม|กัน|ของ|บรรดา|ชาย|และ|หญิง|
+Input: และได้ตกลงใจที่จะส่งเสริมความก้าวหน้าทางสังคม
+Output: |และ|ได้|ตก|ลงใจ|ที่|จะ|ส่ง|เสริม|ความ|ก้าว|หน้า|ทาง|สังคม|
+Input: และมาตรฐานแห่งชีวิตที่ดีขึ้นด้วยในอิสรภาพ
+Output: |และ|มาตรฐาน|แห่ง|ชีวิต|ที่|ดี|ขึ้น|ด้วย|ใน|อิสรภาพ|
+Input: อันกว้างขวางยิ่งขึ้น
+Output: |อัน|กว้าง|ขวาง|ยิ่ง|ขึ้น|
+Input: โดยที่รัฐสมาชิกต่างปฎิญาณจะให้บรรลุถึงซึ่งการส่งเสริมการเคารพและการปฎิบัติตามทั่วสากลต่อสิทธิมนุษยชนและอิสรภาพหลักมูล
+Output: |โดย|ที่|รัฐสมา|ชิก|ต่าง|ปฎิญาณ|จะ|ให้|บรรลุ|ถึง|ซึ่ง|การ|ส่ง|เสริม|การ|เคารพ|และ|การ|ปฎิบัติ|ตาม|ทั่วสากล|ต่อ|สิทธิ|มนุษยชน|และ|อิสรภาพ|หลัก|มู|ล|
+Input: โดยร่วมมือกับสหประชาชาติ
+Output: |โดย|ร่วม|มือ|กับ|สหประชา|ชาติ|
+Input: โดยที่ความเข้าใจร่วมกันในสิทธิ
+Output: |โดย|ที่|ความ|เข้าใจ|ร่วม|กัน|ใน|สิทธิ|
+Input: และอิสรภาพเหล่านี้เป็นสิ่งสำคัญอย่างยิ่ง
+Output: |และ|อิสรภาพ|เหล่า|นี้|เป็น|สิ่ง|สำคัญ|อย่าง|ยิ่ง|
+Input: เพื่อให้ปฏิญาณนี้สำเร็จผลเต็มบริบูรณ์
+Output: |เพื่อ|ให้|ปฏิญาณ|นี้|สำเร็จ|ผล|เต็ม|บริบูรณ์|
+Input: ฉะนั้น
+Output: |ฉะนั้น|
+Input: บัดนี้สมัชชาจึงประกาศว่า
+Output: |บัด|นี้|สมัชชา|จึง|ประกาศ|ว่า|
+Input: ปฏิญญาสากลว่าด้วยสิทธิมนุษยชนนี้
+Output: |ปฏิญญา|สากลว่า|ด้วย|สิทธิ|มนุษยชน|นี้|
+Input: เป็นมาตรฐานร่วมกันแห่งความสำเร็จสำหรับบรรดาประชากรและประชาชาติทั้งหลาย
+Output: |เป็น|มาตรฐาน|ร่วม|กัน|แห่ง|ความ|สำเร็จ|สำหรับ|บรรดา|ประชากร|และ|ประชาชาติ|ทั้ง|หลาย|
+Input: เพื่อจุดหมายปลายทางที่ว่า
+Output: |เพื่อ|จุดหมาย|ปลาย|ทาง|ที่|ว่า|
+Input: เอกชนทุกคนและองค์การชองสังคมทุกองค์การ
+Output: |เอกชน|ทุก|คน|และ|องค์|การ|ชอง|สังคม|ทุก|องค์|การ|
+Input: โดยการรำลึกถึงปฏิญญานี้เป็นเนืองนิจ
+Output: |โดย|การ|รำลึก|ถึง|ปฏิญญา|นี้|เป็น|เนือง|นิจ|
+Input: จะบากบั่นพยายามด้วยการสอนและศึกษา
+Output: |จะ|บาก|บั่นพยายาม|ด้วย|การ|สอน|และ|ศึกษา|
+Input: ในอันที่จะส่งเสริมการเคารพสิทธิและอิสรภาพเหล่านี้
+Output: |ใน|อัน|ที่|จะ|ส่ง|เสริม|การ|เคารพ|สิทธิ|และ|อิสรภาพ|เหล่า|นี้|
+Input: และด้วยมาตรการอันก้าวหน้าทั้งในประเทศและระหว่างประเทศ
+Output: |และ|ด้วย|มาตรการ|อัน|ก้าว|หน้า|ทั้ง|ใน|ประเทศ|และ|ระหว่าง|ประเทศ|
+Input: ในอันที่จะให้มีการยอมรับนับถือ
+Output: |ใน|อัน|ที่|จะ|ให้|มี|การ|ยอม|รับ|นับ|ถือ|
+Input: และการปฏิบัติตามโดยสากลและอย่างเป็นผลจริงจัง
+Output: |และ|การ|ปฏิบัติ|ตาม|โดย|สากล|และ|อย่าง|เป็น|ผล|จริง|จัง|
+Input: ทั้งในบรรดาประชาชนของรัฐสมาชิกด้วยกันเอง
+Output: |ทั้ง|ใน|บรรดา|ประชาชน|ของ|รัฐสมา|ชิก|ด้วย|กัน|เอง|
+Input: และในบรรดาประชาชนของดินแดนที่อยู่ใตัอำนาจของรัฐนั้น
+Output: |และ|ใน|บรรดา|ประชาชน|ของ|ดิน|แดน|ที่|อยู่|ใตัอำนาจ|ของ|รัฐ|นั้น|
+Input: ๆ
+Output: |ๆ|
--- /dev/null
+# Copyright (C) 2018 and later: Unicode, Inc. and others.
+# License & terms of use: http://www.unicode.org/copyright.html
+Model: Thai_graphclust_model4_heavy
+Embedding: grapheme_clusters_tf
+Input: ปฏิญญาสากลว่าด้วยสิทธิมนุษยชน
+Output: |ปฏิญญา|สากลว่า|ด้วย|สิทธิ|มนุ|ษย|ชน|
+Input: คำปรารภ
+Output: คำปราร|ภ|
+Input: โดยที่การยอมรับนับถือเกียรติศักดิ์ประจำตัว
+Output: |โดย|ที่|การ|ยอม|รับ|นับถือเกียรติ|ศักดิ์|ประจำ|ตัว|
+Input: และสิทธิเท่าเทียมกันและโอนมิได้ของบรรดา
+Output: |และ|สิทธิ|เท่า|เทีย|มกัน|และ|โอน|มิได้|ของ|บรรดา|
+Input: สมาชิก
+Output: |สมาชิก|
+Input: ทั้ง
+Output: ทั้ง|
+Input: หลายแห่งครอบครัว
+Output: |หลาย|แห่ง|ครอบ|ครัว|
+Input: มนุษย์เป็นหลักมูลเหตุแห่งอิสรภาพ
+Output: ม|นุ|ษย์|เป็น|หลักมูล|เหตุแห่งอิ|สรภาพ|
+Input: ความยุติธรรม
+Output: |ความ|ยุติธรรม|
+Input: และสันติภาพในโลก
+Output: |และ|สันติภาพ|ใน|โลก|
+Input: โดยที่การไม่นำพาและการเหยียดหยามต่อสิทธิมนุษยชน
+Output: |โดย|ที่|การ|ไม่|นำ|พา|และ|การ|เหยียด|หยาม|ต่อ|สิทธิ|มนุ|ษย|ชน|
+Input: ยังผลให้มีการหระทำอันป่าเถื่อน
+Output: |ยังผล|ให้|มี|การ|หระทำ|อัน|ป่า|เถื่อน|
+Input: ซี่งเป็นการละเมิดมโนธรรมของมนุษยชาติอย่างร้ายแรง
+Output: |ซี่ง|เป็น|การ|ละเมิดม|โนธรรม|ของ|มนุษย|ชาติ|อย่าง|ร้าย|แรง|
+Input: และใต้
+Output: |และ|ใต้|
+Input: ได้
+Output: |ได้|
+Input: มีการประกาศว่า
+Output: |มี|การ|ประกาศ|ว่า|
+Input: ปณิธานสูงสุดของสามัญชนได้แก่ความต้องการให้มนุษย์มีชีวิตอยู่ในโลกด้วยอิสรภาพในการพูด
+Output: |ปณิธา|นสูงสุด|ของ|สามัญชน|ได้|แก่|ความ|ต้อง|การ|ให้|ม|นุษย์|มี|ชีวิต|อยู่|ใน|โลก|ด้วยอิ|สรภาพ|ใน|การ|พูด|
+Input: และความเชื่อถือ
+Output: |และ|ความ|เชื่อถือ|
+Input: และอิสรภาพพ้นจากความหวาดกลัวและความต้องการ
+Output: และอิ|สรภาพพ้น|จาก|ความ|หวาดกลัว|และ|ความ|ต้องการ|
+Input: โดยที่เป็นการจำเป็นอย่างยิ่งที่สิทธิมนุษยชนควรได้รับความคุ้มครองโดยหลักบังคับของกฎหมาย
+Output: |โดย|ที่|เป็น|การ|จำเป็น|อย่าง|ยิ่งที่|สิทธิม|นุ|ษย|ชน|ควร|ได้|รับ|ความ|คุ้มครอง|โดย|หลักบัง|คับ|ของ|กฎหมา|ย|
+Input: ถ้าไม่ประสงค์จะให้คนตกอยู่ในบังคับให้หันเข้าหาการขบถขัดขืนต่อทรราชและการกดขี่เป็นวิถีทางสุดท้าย
+Output: |ถ้า|ไม่|ประสงค์|จะ|ให้|คน|ตก|อยู่|ใน|บังคับ|ให้|หั|นเข้า|หา|การ|ขบ|ถขัด|ขืน|ต่อ|ทรราช|และ|การ|กดขี่|เป็น|วิ|ถี|ทาง|สุดท้าย|
+Input: โดยที่ประชากรแห่งสหประชาชาติได้ยืนยันไว้ในกฎบัตรถึงความเชื่อมั่นในสิทธิมนุษยชนอันเป็นหลักมูล
+Output: |โดย|ที่|ประชากร|แห่ง|สหประชาชาติ|ได้|ยืนยัน|ไว้|ใน|กฎบัตร|ถึง|ความ|เชื่อมั่น|ใน|สิทธิ|มนุ|ษย|ชน|อัน|เป็น|หลักมูล|
+Input: ในเกียรติศักดิ์และคุณค่าของมนุษย์และในสิทธิเท่าเทียมกันของบรรดาชายและหญิง
+Output: |ใน|เกียรติ|ศักดิ์|และ|คุณค่า|ของ|มนุษย์|และ|ใน|สิทธิ|เท่า|เทีย|มกัน|ของ|บรรดา|ชาย|และ|หญิง|
+Input: และได้ตกลงใจที่จะส่งเสริมความก้าวหน้าทางสังคม
+Output: |และ|ได้|ตกลงใจ|ที่|จะ|ส่ง|เสริม|ความ|ก้าว|หน้าทาง|สังคม|
+Input: และมาตรฐานแห่งชีวิตที่ดีขึ้นด้วยในอิสรภาพ
+Output: |และ|มาตรฐาน|แห่งชีวิต|ที่|ดี|ขึ้น|ด้วย|ในอิ|สรภาพ|
+Input: อันกว้างขวางยิ่งขึ้น
+Output: |อัน|กว้าง|ขวาง|ยิ่ง|ขึ้น|
+Input: โดยที่รัฐสมาชิกต่างปฎิญาณจะให้บรรลุถึงซึ่งการส่งเสริมการเคารพและการปฎิบัติตามทั่วสากลต่อสิทธิมนุษยชนและอิสรภาพหลักมูล
+Output: |โดย|ที่|รัฐส|มา|ชิก|ต่าง|ปฎิญาณ|จะ|ให้|บรรลุ|ถึง|ซึ่ง|การ|ส่ง|เสริม|การ|เคา|รพ|และ|การ|ปฎิบัติ|ตา|มทั่วสาก|ล|ต่อ|สิทธิม|นุ|ษย|ชนและอิ|สรภาพ|หลักมูล|
+Input: โดยร่วมมือกับสหประชาชาติ
+Output: |โดย|ร่วมมือ|กับ|สหประชาชาติ|
+Input: โดยที่ความเข้าใจร่วมกันในสิทธิ
+Output: |โดย|ที่|ความ|เข้าใจ|ร่วม|กัน|ใน|สิทธิ|
+Input: และอิสรภาพเหล่านี้เป็นสิ่งสำคัญอย่างยิ่ง
+Output: และอิ|สรภาพ|เหล่า|นี้|เป็น|สิ่ง|สำคัญ|อย่าง|ยิ่ง|
+Input: เพื่อให้ปฏิญาณนี้สำเร็จผลเต็มบริบูรณ์
+Output: |เพื่อ|ให้|ปฏิญาณ|นี้|สำเร็จผล|เต็ม|บริบูรณ์|
+Input: ฉะนั้น
+Output: ฉะนั้น|
+Input: บัดนี้สมัชชาจึงประกาศว่า
+Output: |บัด|นี้|สมัชชา|จึง|ประกาศ|ว่า|
+Input: ปฏิญญาสากลว่าด้วยสิทธิมนุษยชนนี้
+Output: |ปฏิญญา|สากลว่า|ด้วย|สิทธิ|มนุ|ษย|ชน|นี้|
+Input: เป็นมาตรฐานร่วมกันแห่งความสำเร็จสำหรับบรรดาประชากรและประชาชาติทั้งหลาย
+Output: |เป็น|มาตรฐาน|ร่วม|กัน|แห่ง|ความ|สำเร็จ|สำหรับ|บรรดา|ประชากร|และ|ประชาชาติ|ทั้งหลา|ย|
+Input: เพื่อจุดหมายปลายทางที่ว่า
+Output: |เพื่อจุดหมาย|ปลาย|ทาง|ที่|ว่า|
+Input: เอกชนทุกคนและองค์การชองสังคมทุกองค์การ
+Output: |เอกชน|ทุก|คน|และ|องค์การ|ชอง|สังคม|ทุกองค์การ|
+Input: โดยการรำลึกถึงปฏิญญานี้เป็นเนืองนิจ
+Output: |โดย|การ|รำลึก|ถึง|ปฏิญญานี้|เป็น|เนือง|นิ|จ|
+Input: จะบากบั่นพยายามด้วยการสอนและศึกษา
+Output: |จะ|บาก|บั่น|พยายาม|ด้วย|การ|สอน|และ|ศึก|ษา|
+Input: ในอันที่จะส่งเสริมการเคารพสิทธิและอิสรภาพเหล่านี้
+Output: |ใน|อัน|ที่|จะ|ส่ง|เสริม|การ|เคารพ|สิทธิ|และอิ|สรภาพ|เหล่า|นี้|
+Input: และด้วยมาตรการอันก้าวหน้าทั้งในประเทศและระหว่างประเทศ
+Output: |และ|ด้วย|มาตรการ|อัน|ก้าว|หน้าทั้ง|ใน|ประเทศ|และ|ระหว่าง|ประเทศ|
+Input: ในอันที่จะให้มีการยอมรับนับถือ
+Output: |ใน|อัน|ที่|จะ|ให้|มี|การ|ยอม|รับ|นับถือ|
+Input: และการปฏิบัติตามโดยสากลและอย่างเป็นผลจริงจัง
+Output: |และ|การ|ปฏิบัติตาม|โดย|สากล|และ|อย่าง|เป็นผล|จริง|จัง|
+Input: ทั้งในบรรดาประชาชนของรัฐสมาชิกด้วยกันเอง
+Output: ทั้ง|ใน|บรรดา|ประชาชน|ของ|รัฐส|มาชิก|ด้วย|กัน|เอง|
+Input: และในบรรดาประชาชนของดินแดนที่อยู่ใตัอำนาจของรัฐนั้น
+Output: |และ|ใน|บรรดา|ประชาชน|ของ|ดินแดน|ที่|อยู่|ใตัอำนาจ|ของ|รัฐนั้น|
+Input: ๆ
+Output: |ๆ|
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Locale;
+import java.util.MissingResourceException;
+
+import com.ibm.icu.impl.breakiter.LSTMBreakEngine;
+import com.ibm.icu.lang.UScript;
public final class TestUtil {
/**
}
return ver;
}
+
+ private static boolean lstmDataIsBuilt() {
+ try {
+ LSTMBreakEngine.createData(UScript.THAI);
+ return true;
+ } catch (MissingResourceException e) {
+ // do nothing
+ }
+ try {
+ LSTMBreakEngine.createData(UScript.MYANMAR);
+ return true;
+ } catch (MissingResourceException e) {
+ // do nothing
+ }
+ return false;
+ }
+
+ public static boolean skipLSTMTest() {
+ return ! lstmDataIsBuilt();
+ }
+
+ public static boolean skipDictionaryTest() {
+ return lstmDataIsBuilt();
+ }
}
*/
@Test
public void TestThai() {
+ // The expectations in this test heavily depends on the Thai dictionary.
+ // Therefore, we skip this test under the LSTM configuration.
+ org.junit.Assume.assumeTrue(!TestUtil.skipDictionaryTest());
Transliterator tr = Transliterator.getInstance("Any-Latin", Transliterator.FORWARD);
String thaiText =
"\u0e42\u0e14\u0e22\u0e1e\u0e37\u0e49\u0e19\u0e10\u0e32\u0e19\u0e41\u0e25\u0e49\u0e27, \u0e04\u0e2d" +