]> gitweb.fperrin.net Git - Dictionary.git/blobdiff - jars/icu4j-4_2_1-src/src/com/ibm/icu/impl/UnicodeRegex.java
go
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / icu / impl / UnicodeRegex.java
old mode 100755 (executable)
new mode 100644 (file)
index 19fa724..8aab454
-//##header\r
-//#if defined(FOUNDATION10) || defined(J2SE13) || defined(J2SE14)\r
-//#else\r
-/*\r
- *******************************************************************************\r
- * Copyright (C) 2009, Google, International Business Machines Corporation and *\r
- * others. All Rights Reserved.                                                *\r
- *******************************************************************************\r
- */\r
-package com.ibm.icu.impl;\r
-\r
-import java.io.BufferedReader;\r
-import java.io.FileInputStream;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
-import java.io.InputStreamReader;\r
-import java.io.UnsupportedEncodingException;\r
-import java.text.ParsePosition;\r
-import java.util.Arrays;\r
-import java.util.Comparator;\r
-import java.util.Iterator;\r
-import java.util.LinkedHashSet;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-import java.util.TreeMap;\r
-import java.util.regex.Pattern;\r
-\r
-import com.ibm.icu.text.StringTransform;\r
-import com.ibm.icu.text.UnicodeSet;\r
-import com.ibm.icu.util.Freezable;\r
-\r
-/**\r
- * Contains utilities to supplement the JDK Regex, since it doesn't handle\r
- * Unicode well.\r
- * \r
- * @author markdavis\r
- */\r
-public class UnicodeRegex implements Cloneable, Freezable, StringTransform {\r
-    // Note: we don't currently have any state, but intend to in the future,\r
-    // particularly for the regex style supported.\r
-\r
-    /**\r
-     * Adds full Unicode property support, with the latest version of Unicode,\r
-     * to Java Regex, bringing it up to Level 1 (see\r
-     * http://www.unicode.org/reports/tr18/). It does this by preprocessing the\r
-     * regex pattern string and interpreting the character classes (\p{...},\r
-     * \P{...}, [...]) according to their syntax and meaning in UnicodeSet. With\r
-     * this utility, Java regex expressions can be updated to work with the\r
-     * latest version of Unicode, and with all Unicode properties. Note that the\r
-     * UnicodeSet syntax has not yet, however, been updated to be completely\r
-     * consistent with Java regex, so be careful of the differences.\r
-     * <p>Not thread-safe; create a separate copy for different threads.\r
-     * <p>In the future, we may extend this to support other regex packages.\r
-     * \r
-     * @regex A modified Java regex pattern, as in the input to\r
-     *        Pattern.compile(), except that all "character classes" are\r
-     *        processed as if they were UnicodeSet patterns. Example:\r
-     *        "abc[:bc=N:]. See UnicodeSet for the differences in syntax.\r
-     * @return A processed Java regex pattern, suitable for input to\r
-     *         Pattern.compile().\r
-     */\r
-    public String transform(String regex) {\r
-        StringBuffer result = new StringBuffer();\r
-        UnicodeSet temp = new UnicodeSet();\r
-        ParsePosition pos = new ParsePosition(0);\r
-        int state = 0; // 1 = after \\r
-\r
-        // We add each character unmodified to the output, unless we have a\r
-        // UnicodeSet. Note that we don't worry about supplementary characters,\r
-        // since none of the syntax uses them.\r
-\r
-        for (int i = 0; i < regex.length(); ++i) {\r
-            // look for UnicodeSets, allowing for quoting with \ and \Q\r
-            char ch = regex.charAt(i);\r
-            switch (state) {\r
-            case 0: // we only care about \, and '['.\r
-                if (ch == '\\') {\r
-                    if (UnicodeSet.resemblesPattern(regex, i)) {\r
-                        // should only happen with \p\r
-                        i = processSet(regex, i, result, temp, pos);\r
-                        continue;\r
-                    }\r
-                    state = 1;\r
-                } else if (ch == '[') {\r
-                    // if we have what looks like a UnicodeSet\r
-                    if (UnicodeSet.resemblesPattern(regex, i)) {\r
-                        i = processSet(regex, i, result, temp, pos);\r
-                        continue;\r
-                    }\r
-                }\r
-                break;\r
-\r
-            case 1: // we are after a \\r
-                if (ch == 'Q') {\r
-                    state = 1;\r
-                } else {\r
-                    state = 0;\r
-                }\r
-                break;\r
-\r
-            case 2: // we are in a \Q...\r
-                if (ch == '\\') {\r
-                    state = 3;\r
-                }\r
-                break;\r
-\r
-            case 3: // we are in at \Q...\\r
-                if (ch == 'E') {\r
-                    state = 0;\r
-                }\r
-                state = 2;\r
-                break;\r
-            }\r
-            result.append(ch);\r
-        }\r
-        return result.toString();\r
-    }\r
-\r
-    /**\r
-     * Convenience static function, using standard parameters.\r
-     * @param regex as in process()\r
-     * @return processed regex pattern, as in process()\r
-     */\r
-    public static String fix(String regex) {\r
-        return STANDARD.transform(regex);\r
-    }\r
-\r
-    /**\r
-     * Compile a regex string, after processing by fix(...).\r
-     * \r
-     * @param regex\r
-     *            Raw regex pattern, as in fix(...).\r
-     * @return Pattern\r
-     */\r
-    public static Pattern compile(String regex) {\r
-        return Pattern.compile(STANDARD.transform(regex));\r
-    }\r
-\r
-    /**\r
-     * Compile a regex string, after processing by fix(...).\r
-     * \r
-     * @param regex\r
-     *            Raw regex pattern, as in fix(...).\r
-     * @return Pattern\r
-     */\r
-    public static Pattern compile(String regex, int options) {\r
-        return Pattern.compile(STANDARD.transform(regex), options);\r
-    }\r
-\r
-    /**\r
-     * Compile a composed string from a set of BNF lines; see the List version for more information.\r
-     * \r
-     * @param bnfLines Series of BNF lines.\r
-     * @return Pattern\r
-     */\r
-    public String compileBnf(String bnfLines) {\r
-        return compileBnf(Arrays.asList(bnfLines.split("\\r\\n?|\\n")));\r
-    }\r
-\r
-    /**\r
-     * Compile a composed string from a set of BNF lines, such as for composing a regex\r
-     * expression. The lines can be in any order, but there must not be any\r
-     * cycles. The result can be used as input for fix().\r
-     * <p>\r
-     * Example:\r
-     * <pre>\r
-     * uri = (?: (scheme) \\:)? (host) (?: \\? (query))? (?: \\u0023 (fragment))?;\r
-     * scheme = reserved+;\r
-     * host = // reserved+;\r
-     * query = [\\=reserved]+;\r
-     * fragment = reserved+;\r
-     * reserved = [[:ascii:][:alphabetic:]];\r
-     * </pre>\r
-     * <p>\r
-     * Caveats: at this point the parsing is simple; for example, # cannot be\r
-     * quoted (use \\u0023); you can set it to null to disable. \r
-     * The equality sign and a few others can be reset with\r
-     * setBnfX().\r
-     * \r
-     * @param bnfLines\r
-     *          Series of lines that represent a BNF expression. The lines contain\r
-     *          a series of statements that of the form x=y;. A statement can take\r
-     *          multiple lines, but there can't be multiple statements on a line.\r
-     *          A hash quotes to the end of the line.\r
-     * @return Pattern\r
-     */\r
-    public String compileBnf(List lines) {\r
-        Map variables = getVariables(lines);\r
-        Set unused = new LinkedHashSet(variables.keySet());\r
-        // brute force replacement; do twice to allow for different order\r
-        // later on can optimize\r
-        for (int i = 0; i < 2; ++i) {\r
-            for (Iterator it = variables.keySet().iterator(); it.hasNext();) {\r
-                String variable = (String) it.next();\r
-                String definition = (String) variables.get(variable);\r
-                for (Iterator it2 = variables.keySet().iterator(); it2.hasNext();) {\r
-                    String variable2 = (String) it2.next();\r
-                    if (variable.equals(variable2)) continue;\r
-                    String definition2 = (String) variables.get(variable2);\r
-                    String altered2 = definition2.replace(variable, definition);\r
-                    if (!altered2.equals(definition2)) {\r
-                        unused.remove(variable);\r
-                        variables.put(variable2, altered2);\r
-                        if (log != null) {\r
-                            try {\r
-                                log.append(variable2 + "=" + altered2 + ";");\r
-                            } catch (IOException e) {\r
-                                throw (IllegalArgumentException) new IllegalArgumentException().initCause(e);\r
-                            }\r
-                        }\r
-                    }\r
-                }\r
-            }\r
-        }\r
-        if (unused.size() != 1) {\r
-            throw new IllegalArgumentException("Not a single root: " + unused);\r
-        }\r
-        return (String) variables.get(unused.iterator().next());\r
-    }\r
-\r
-    public String getBnfCommentString() {\r
-        return bnfCommentString;\r
-    }\r
-\r
-    public void setBnfCommentString(String bnfCommentString) {\r
-        this.bnfCommentString = bnfCommentString;\r
-    }\r
-\r
-    public String getBnfVariableInfix() {\r
-        return bnfVariableInfix;\r
-    }\r
-\r
-    public void setBnfVariableInfix(String bnfVariableInfix) {\r
-        this.bnfVariableInfix = bnfVariableInfix;\r
-    }\r
-\r
-    public String getBnfLineSeparator() {\r
-        return bnfLineSeparator;\r
-    }\r
-\r
-    public void setBnfLineSeparator(String bnfLineSeparator) {\r
-        this.bnfLineSeparator = bnfLineSeparator;\r
-    }\r
-\r
-    /**\r
-     * Utility for loading lines from a file.\r
-     * @param result\r
-     * @param file\r
-     * @param encoding if null, then UTF-8\r
-     * @return filled list\r
-     * @throws IOException\r
-     */\r
-    public static List appendLines(List result, String file, String encoding) throws IOException {\r
-        return appendLines(result, new FileInputStream(file), encoding);\r
-    }\r
-\r
-    /**\r
-     * Utility for loading lines from a UTF8 file.\r
-     * @param result\r
-     * @param inputStream\r
-     * @param encoding if null, then UTF-8\r
-     * @return filled list\r
-     * @throws IOException\r
-     */\r
-    public static List appendLines(List result, InputStream inputStream, String encoding)\r
-            throws UnsupportedEncodingException, IOException {\r
-        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, encoding == null ? "UTF-8" : encoding));\r
-        while (true) {\r
-            String line = in.readLine();\r
-            if (line == null) break;\r
-            result.add(line);\r
-        }\r
-        return result;\r
-    }\r
-    \r
-    \r
-\r
-    /* (non-Javadoc)\r
-     * @see com.ibm.icu.util.Freezable#cloneAsThawed()\r
-     */\r
-    public Object cloneAsThawed() {\r
-        // TODO Auto-generated method stub\r
-        try {\r
-            return this.clone();\r
-        } catch (CloneNotSupportedException e) {\r
-            throw new IllegalArgumentException(); // should never happen\r
-        }\r
-    }\r
-\r
-    /* (non-Javadoc)\r
-     * @see com.ibm.icu.util.Freezable#freeze()\r
-     */\r
-    public Object freeze() {\r
-        // no action needed now.\r
-        return this;\r
-    }\r
-\r
-    /* (non-Javadoc)\r
-     * @see com.ibm.icu.util.Freezable#isFrozen()\r
-     */\r
-    public boolean isFrozen() {\r
-        // at this point, always true\r
-        return true;\r
-    }\r
-\r
-    // ===== PRIVATES =====\r
-\r
-    private int processSet(String regex, int i, StringBuffer result, UnicodeSet temp, ParsePosition pos) {\r
-        try {\r
-            pos.setIndex(i);\r
-            UnicodeSet x = temp.clear().applyPattern(regex, pos, null, 0);\r
-            x.complement().complement(); // hack to fix toPattern\r
-            result.append(x.toPattern(false));\r
-            i = pos.getIndex() - 1; // allow for the loop increment\r
-            return i;\r
-        } catch (Exception e) {\r
-            throw (IllegalArgumentException) new IllegalArgumentException("Error in " + regex).initCause(e);\r
-        }\r
-    }\r
-\r
-    private static UnicodeRegex STANDARD = new UnicodeRegex();\r
-    private String bnfCommentString = "#";\r
-    private String bnfVariableInfix = "=";\r
-    private String bnfLineSeparator = "\n";\r
-    private Appendable log = null;\r
-\r
-    private Comparator LongestFirst = new Comparator () {\r
-        public int compare(Object obj0, Object obj1) {\r
-            String arg0 = obj0.toString();\r
-            String arg1 = obj1.toString();\r
-            int len0 = arg0.length();\r
-            int len1 = arg1.length();\r
-            if (len0 != len1) return len1 - len0;\r
-            return arg0.compareTo(arg1);\r
-        }\r
-    };\r
-\r
-    private Map getVariables(List lines) {\r
-        Map variables = new TreeMap(LongestFirst);\r
-        String variable = null;\r
-        StringBuffer definition = new StringBuffer();\r
-        int count = 0;\r
-        for (Iterator it = lines.iterator(); it.hasNext();) {\r
-            String line = (String)it.next();\r
-            ++count;\r
-            // remove initial bom, comments\r
-            if (line.length() == 0) continue;\r
-            if (line.charAt(0) == '\uFEFF') line = line.substring(1);\r
-\r
-            if (bnfCommentString != null) {\r
-                int hashPos = line.indexOf(bnfCommentString);\r
-                if (hashPos >= 0) line = line.substring(0, hashPos);\r
-            }\r
-            String trimline = line.trim();\r
-            if (trimline.length() == 0) continue;\r
-\r
-            // String[] lineParts = line.split(";");\r
-            String linePart = line; // lineParts[i]; // .trim().replace("\\s+", " ");\r
-            if (linePart.trim().length() == 0) continue;\r
-            boolean terminated = trimline.endsWith(";");\r
-            if (terminated) {\r
-                linePart = linePart.substring(0,linePart.lastIndexOf(';'));\r
-            }\r
-            int equalsPos = linePart.indexOf(bnfVariableInfix);\r
-            if (equalsPos >= 0) {\r
-                if (variable != null) {\r
-                    throw new IllegalArgumentException("Missing ';' before " + count + ") " + line);\r
-                }\r
-                variable = linePart.substring(0,equalsPos).trim();\r
-                if (variables.containsKey(variable)) {\r
-                    throw new IllegalArgumentException("Duplicate variable definition in " + line);\r
-                }\r
-                definition.append(linePart.substring(equalsPos+1).trim());\r
-            } else { // no equals, so\r
-                if (variable == null) {\r
-                    throw new IllegalArgumentException("Missing '=' at " + count + ") " + line);\r
-                }\r
-                definition.append(bnfLineSeparator).append(linePart);\r
-            }\r
-            // we are terminated if i is not at the end, or the line ends with a ;\r
-            if (terminated) {\r
-                variables.put(variable, definition.toString());\r
-                variable = null; // signal we have no variable\r
-                definition.setLength(0);\r
-            }\r
-        }\r
-        if (variable != null) {\r
-            throw new IllegalArgumentException("Missing ';' at end");\r
-        }\r
-        return variables;\r
-    }\r
-}\r
-//#endif\r
-\r
+//##header J2SE15
+//#if defined(FOUNDATION10) || defined(J2SE13) || defined(J2SE14)
+//#else
+/*
+ *******************************************************************************
+ * Copyright (C) 2009, Google, International Business Machines Corporation and *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.impl;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.text.ParsePosition;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.regex.Pattern;
+
+import com.ibm.icu.text.StringTransform;
+import com.ibm.icu.text.UnicodeSet;
+import com.ibm.icu.util.Freezable;
+
+/**
+ * Contains utilities to supplement the JDK Regex, since it doesn't handle
+ * Unicode well.
+ * 
+ * @author markdavis
+ */
+public class UnicodeRegex implements Cloneable, Freezable, StringTransform {
+    // Note: we don't currently have any state, but intend to in the future,
+    // particularly for the regex style supported.
+
+    /**
+     * Adds full Unicode property support, with the latest version of Unicode,
+     * to Java Regex, bringing it up to Level 1 (see
+     * http://www.unicode.org/reports/tr18/). It does this by preprocessing the
+     * regex pattern string and interpreting the character classes (\p{...},
+     * \P{...}, [...]) according to their syntax and meaning in UnicodeSet. With
+     * this utility, Java regex expressions can be updated to work with the
+     * latest version of Unicode, and with all Unicode properties. Note that the
+     * UnicodeSet syntax has not yet, however, been updated to be completely
+     * consistent with Java regex, so be careful of the differences.
+     * <p>Not thread-safe; create a separate copy for different threads.
+     * <p>In the future, we may extend this to support other regex packages.
+     * 
+     * @regex A modified Java regex pattern, as in the input to
+     *        Pattern.compile(), except that all "character classes" are
+     *        processed as if they were UnicodeSet patterns. Example:
+     *        "abc[:bc=N:]. See UnicodeSet for the differences in syntax.
+     * @return A processed Java regex pattern, suitable for input to
+     *         Pattern.compile().
+     */
+    public String transform(String regex) {
+        StringBuffer result = new StringBuffer();
+        UnicodeSet temp = new UnicodeSet();
+        ParsePosition pos = new ParsePosition(0);
+        int state = 0; // 1 = after \
+
+        // We add each character unmodified to the output, unless we have a
+        // UnicodeSet. Note that we don't worry about supplementary characters,
+        // since none of the syntax uses them.
+
+        for (int i = 0; i < regex.length(); ++i) {
+            // look for UnicodeSets, allowing for quoting with \ and \Q
+            char ch = regex.charAt(i);
+            switch (state) {
+            case 0: // we only care about \, and '['.
+                if (ch == '\\') {
+                    if (UnicodeSet.resemblesPattern(regex, i)) {
+                        // should only happen with \p
+                        i = processSet(regex, i, result, temp, pos);
+                        continue;
+                    }
+                    state = 1;
+                } else if (ch == '[') {
+                    // if we have what looks like a UnicodeSet
+                    if (UnicodeSet.resemblesPattern(regex, i)) {
+                        i = processSet(regex, i, result, temp, pos);
+                        continue;
+                    }
+                }
+                break;
+
+            case 1: // we are after a \
+                if (ch == 'Q') {
+                    state = 1;
+                } else {
+                    state = 0;
+                }
+                break;
+
+            case 2: // we are in a \Q...
+                if (ch == '\\') {
+                    state = 3;
+                }
+                break;
+
+            case 3: // we are in at \Q...\
+                if (ch == 'E') {
+                    state = 0;
+                }
+                state = 2;
+                break;
+            }
+            result.append(ch);
+        }
+        return result.toString();
+    }
+
+    /**
+     * Convenience static function, using standard parameters.
+     * @param regex as in process()
+     * @return processed regex pattern, as in process()
+     */
+    public static String fix(String regex) {
+        return STANDARD.transform(regex);
+    }
+
+    /**
+     * Compile a regex string, after processing by fix(...).
+     * 
+     * @param regex
+     *            Raw regex pattern, as in fix(...).
+     * @return Pattern
+     */
+    public static Pattern compile(String regex) {
+        return Pattern.compile(STANDARD.transform(regex));
+    }
+
+    /**
+     * Compile a regex string, after processing by fix(...).
+     * 
+     * @param regex
+     *            Raw regex pattern, as in fix(...).
+     * @return Pattern
+     */
+    public static Pattern compile(String regex, int options) {
+        return Pattern.compile(STANDARD.transform(regex), options);
+    }
+
+    /**
+     * Compile a composed string from a set of BNF lines; see the List version for more information.
+     * 
+     * @param bnfLines Series of BNF lines.
+     * @return Pattern
+     */
+    public String compileBnf(String bnfLines) {
+        return compileBnf(Arrays.asList(bnfLines.split("\\r\\n?|\\n")));
+    }
+
+    /**
+     * Compile a composed string from a set of BNF lines, such as for composing a regex
+     * expression. The lines can be in any order, but there must not be any
+     * cycles. The result can be used as input for fix().
+     * <p>
+     * Example:
+     * <pre>
+     * uri = (?: (scheme) \\:)? (host) (?: \\? (query))? (?: \\u0023 (fragment))?;
+     * scheme = reserved+;
+     * host = // reserved+;
+     * query = [\\=reserved]+;
+     * fragment = reserved+;
+     * reserved = [[:ascii:][:alphabetic:]];
+     * </pre>
+     * <p>
+     * Caveats: at this point the parsing is simple; for example, # cannot be
+     * quoted (use \\u0023); you can set it to null to disable. 
+     * The equality sign and a few others can be reset with
+     * setBnfX().
+     * 
+     * @param bnfLines
+     *          Series of lines that represent a BNF expression. The lines contain
+     *          a series of statements that of the form x=y;. A statement can take
+     *          multiple lines, but there can't be multiple statements on a line.
+     *          A hash quotes to the end of the line.
+     * @return Pattern
+     */
+    public String compileBnf(List lines) {
+        Map variables = getVariables(lines);
+        Set unused = new LinkedHashSet(variables.keySet());
+        // brute force replacement; do twice to allow for different order
+        // later on can optimize
+        for (int i = 0; i < 2; ++i) {
+            for (Iterator it = variables.keySet().iterator(); it.hasNext();) {
+                String variable = (String) it.next();
+                String definition = (String) variables.get(variable);
+                for (Iterator it2 = variables.keySet().iterator(); it2.hasNext();) {
+                    String variable2 = (String) it2.next();
+                    if (variable.equals(variable2)) continue;
+                    String definition2 = (String) variables.get(variable2);
+                    String altered2 = definition2.replace(variable, definition);
+                    if (!altered2.equals(definition2)) {
+                        unused.remove(variable);
+                        variables.put(variable2, altered2);
+                        if (log != null) {
+                            try {
+                                log.append(variable2 + "=" + altered2 + ";");
+                            } catch (IOException e) {
+                                throw (IllegalArgumentException) new IllegalArgumentException().initCause(e);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (unused.size() != 1) {
+            throw new IllegalArgumentException("Not a single root: " + unused);
+        }
+        return (String) variables.get(unused.iterator().next());
+    }
+
+    public String getBnfCommentString() {
+        return bnfCommentString;
+    }
+
+    public void setBnfCommentString(String bnfCommentString) {
+        this.bnfCommentString = bnfCommentString;
+    }
+
+    public String getBnfVariableInfix() {
+        return bnfVariableInfix;
+    }
+
+    public void setBnfVariableInfix(String bnfVariableInfix) {
+        this.bnfVariableInfix = bnfVariableInfix;
+    }
+
+    public String getBnfLineSeparator() {
+        return bnfLineSeparator;
+    }
+
+    public void setBnfLineSeparator(String bnfLineSeparator) {
+        this.bnfLineSeparator = bnfLineSeparator;
+    }
+
+    /**
+     * Utility for loading lines from a file.
+     * @param result
+     * @param file
+     * @param encoding if null, then UTF-8
+     * @return filled list
+     * @throws IOException
+     */
+    public static List appendLines(List result, String file, String encoding) throws IOException {
+        return appendLines(result, new FileInputStream(file), encoding);
+    }
+
+    /**
+     * Utility for loading lines from a UTF8 file.
+     * @param result
+     * @param inputStream
+     * @param encoding if null, then UTF-8
+     * @return filled list
+     * @throws IOException
+     */
+    public static List appendLines(List result, InputStream inputStream, String encoding)
+            throws UnsupportedEncodingException, IOException {
+        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, encoding == null ? "UTF-8" : encoding));
+        while (true) {
+            String line = in.readLine();
+            if (line == null) break;
+            result.add(line);
+        }
+        return result;
+    }
+    
+    
+
+    /* (non-Javadoc)
+     * @see com.ibm.icu.util.Freezable#cloneAsThawed()
+     */
+    public Object cloneAsThawed() {
+        // TODO Auto-generated method stub
+        try {
+            return this.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new IllegalArgumentException(); // should never happen
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see com.ibm.icu.util.Freezable#freeze()
+     */
+    public Object freeze() {
+        // no action needed now.
+        return this;
+    }
+
+    /* (non-Javadoc)
+     * @see com.ibm.icu.util.Freezable#isFrozen()
+     */
+    public boolean isFrozen() {
+        // at this point, always true
+        return true;
+    }
+
+    // ===== PRIVATES =====
+
+    private int processSet(String regex, int i, StringBuffer result, UnicodeSet temp, ParsePosition pos) {
+        try {
+            pos.setIndex(i);
+            UnicodeSet x = temp.clear().applyPattern(regex, pos, null, 0);
+            x.complement().complement(); // hack to fix toPattern
+            result.append(x.toPattern(false));
+            i = pos.getIndex() - 1; // allow for the loop increment
+            return i;
+        } catch (Exception e) {
+            throw (IllegalArgumentException) new IllegalArgumentException("Error in " + regex).initCause(e);
+        }
+    }
+
+    private static UnicodeRegex STANDARD = new UnicodeRegex();
+    private String bnfCommentString = "#";
+    private String bnfVariableInfix = "=";
+    private String bnfLineSeparator = "\n";
+    private Appendable log = null;
+
+    private Comparator LongestFirst = new Comparator () {
+        public int compare(Object obj0, Object obj1) {
+            String arg0 = obj0.toString();
+            String arg1 = obj1.toString();
+            int len0 = arg0.length();
+            int len1 = arg1.length();
+            if (len0 != len1) return len1 - len0;
+            return arg0.compareTo(arg1);
+        }
+    };
+
+    private Map getVariables(List lines) {
+        Map variables = new TreeMap(LongestFirst);
+        String variable = null;
+        StringBuffer definition = new StringBuffer();
+        int count = 0;
+        for (Iterator it = lines.iterator(); it.hasNext();) {
+            String line = (String)it.next();
+            ++count;
+            // remove initial bom, comments
+            if (line.length() == 0) continue;
+            if (line.charAt(0) == '\uFEFF') line = line.substring(1);
+
+            if (bnfCommentString != null) {
+                int hashPos = line.indexOf(bnfCommentString);
+                if (hashPos >= 0) line = line.substring(0, hashPos);
+            }
+            String trimline = line.trim();
+            if (trimline.length() == 0) continue;
+
+            // String[] lineParts = line.split(";");
+            String linePart = line; // lineParts[i]; // .trim().replace("\\s+", " ");
+            if (linePart.trim().length() == 0) continue;
+            boolean terminated = trimline.endsWith(";");
+            if (terminated) {
+                linePart = linePart.substring(0,linePart.lastIndexOf(';'));
+            }
+            int equalsPos = linePart.indexOf(bnfVariableInfix);
+            if (equalsPos >= 0) {
+                if (variable != null) {
+                    throw new IllegalArgumentException("Missing ';' before " + count + ") " + line);
+                }
+                variable = linePart.substring(0,equalsPos).trim();
+                if (variables.containsKey(variable)) {
+                    throw new IllegalArgumentException("Duplicate variable definition in " + line);
+                }
+                definition.append(linePart.substring(equalsPos+1).trim());
+            } else { // no equals, so
+                if (variable == null) {
+                    throw new IllegalArgumentException("Missing '=' at " + count + ") " + line);
+                }
+                definition.append(bnfLineSeparator).append(linePart);
+            }
+            // we are terminated if i is not at the end, or the line ends with a ;
+            if (terminated) {
+                variables.put(variable, definition.toString());
+                variable = null; // signal we have no variable
+                definition.setLength(0);
+            }
+        }
+        if (variable != null) {
+            throw new IllegalArgumentException("Missing ';' at end");
+        }
+        return variables;
+    }
+}
+//#endif
+