?? maps.java
字號:
/* Maps.java{{IS_NOTE Purpose: Utilities for Map Description: History: 2001/4/25, Tom M. Yeh: Created.}}IS_NOTECopyright (C) 2001 Potix Corporation. All Rights Reserved.{{IS_RIGHT This program is distributed under GPL Version 2.0 in the hope that it will be useful, but WITHOUT ANY WARRANTY.}}IS_RIGHT*/package org.zkoss.util;import java.util.List;import java.util.LinkedList;import java.util.Map;import java.util.HashMap;import java.util.Iterator;import java.io.IOException;import java.io.InputStream;import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.PushbackInputStream;import org.zkoss.lang.D;import org.zkoss.lang.Strings;import org.zkoss.mesg.MCommon;import org.zkoss.util.logging.Log;/** * Utilities for process Map. * * @author tomyeh */public class Maps { private static final Log log = Log.lookup(Maps.class); /** * Reads a property list (key and element pairs) from the input stream, * by specifying the charset. * <p>Like java.util.Properties, it translates \\u, \n, \r, \t and \f. * However, it enhanced Properties as follows. * * <ul> * <li>It accepts any charset, not just 8859-1.</li> * <li>It uses a different syntax to let value spread over multiple * lines, descrubed below.</li> * <li>Whitespace is trimmed around '=' and at the beginning of * the key and the ending of the value.</li> * <li>Illegal lines are ignored (Properties.load considers it * as a key with an empty value).</li> * <li>Only '=' is accepted as the separator of key and value.</li> * <li>Only '#' is accepted as comment lines.</li> * </ul> * * <p>To spead a value over multiple lines, you could, * unlike java.util.Properties.load, append '{' to the end of a line. * Then, all the following lines are considerred as part of a value, * unless encountering a line containing only one '}'.<br> * Example: * <pre><code>abc = { *line 1 *line 2 *} *xyz = { *line 1 *line 2 *}</code></pre> * * <p>Moreover, you could prefix a group of keys with certain prefix: * <pre><code>org.zkoss.some. { * a = aaa * b = bbb *}</code></pre> * * It actually defines two keys: "org.zkoss.some.a" and "org.zkoss.some.b". * * <p>Note: (1) whitespace in the {...} block are all preserved.<br> * (2) if only whitespaces is between '=' and '{', they are ignored. * * @param charset the charset; if null, it detects UTF-16 BOM (0xfe 0xff * or 0xff 0xfe). If no UTF-16 BOM, UTF-8 is always assumed. * Note 1: UTF-8's BOM (0xef 0xbb 0xbf) is optional, so we don't count on it. * Note 2: ISO-8859-1 is not used because we cannot tell its difference * from UTF-8 (while some of our properties files are in UTF-8). * * @param caseInsensitive whether the key used to access the map * is case-insensitive. If true, all keys are converted to lower cases. */ public final static void load(Map map, InputStream sm, String charset, boolean caseInsensitive) throws IOException { final PushbackInputStream pis = new PushbackInputStream(sm, 3); if (charset == null || charset.startsWith("UTF")) { final byte[] ahead = new byte[3]; int n = pis.read(ahead); if (n >= 2 && ((ahead[0] == (byte)0xfe && ahead[1] == (byte)0xff) || (ahead[0] == (byte)0xff && ahead[1] == (byte)0xfe))) { charset = "UTF-16"; //don't eat UTF-16 BOM, since Java use it to know endian } else if (n == 3 && ahead[0] == (byte)0xef && ahead[1] == (byte)0xbb && ahead[2] == (byte)0xbf) { charset = "UTF-8"; n = 0; //eat UTF-8 BOM since Java won't handle it } else if (charset == null) { charset = "UTF-8"; } if (n > 0) pis.unread(ahead, 0, n); } final BufferedReader in = new BufferedReader(new InputStreamReader(pis, charset)); final List prefixes = new LinkedList(); String prefix = null; String line; for (int lno = 1; (line = in.readLine()) != null; ++lno) { int len = line.length(); if (len == 0) continue; final Strings.Result res = Strings.nextToken(line, 0, new char[] {'=', '{', '}'}, true, false); if (res == null || res.token.startsWith("#")) continue; //nothing found if (res.separator == (char)0) { if (res.token.length() > 0) log.warning(">>Igored: a key, "+res.token+", without value, line "+lno); continue; } if (res.separator == '{') { //res.token.lenth() could be zero if (Strings.skipWhitespaces(line, res.next) < len) //non-space following '{' throw new IllegalSyntaxException("Invalid nest: '{' must be the last character, line "+lno); prefixes.add(new Integer(res.token.length())); prefix = prefix != null ? prefix + res.token: res.token; continue; } if (res.separator == '}' ) { if (Strings.skipWhitespaces(line, res.next) < len) //non-space following '}' throw new IllegalSyntaxException("Invalid nesting: '}' must be the last character, line "+lno); if (prefixes.isEmpty()) throw new IllegalSyntaxException("Invalid nesting: '}' does have any preceding '{', line "+lno); final Integer i = (Integer)prefixes.remove(prefixes.size() - 1); //pop prefix = prefixes.isEmpty() ? null: prefix.substring(0, prefix.length() - i.intValue()); continue; } if (res.token.length() == 0) { log.warning(">>Ignored: wihout key, line "+lno); continue; }// assert res.separator == '=': "Wrong separator: "+res.separator; final String val; String key = caseInsensitive ? res.token.toLowerCase(): res.token; int j = Strings.skipWhitespaces(line, res.next); int k = Strings.skipWhitespacesBackward(line, len - 1); if (j == k && line.charAt(k) == '{') { //pack multiple lines final StringBuffer sb = new StringBuffer(); for (int lnoFrom = lno;;) { line = in.readLine(); ++lno; if (line == null){ log.warning( ">>Ignored: invalid multiple-line format: '={' does not have following '}', "+lnoFrom); break; } len = line.length(); if (len > 0) { j = Strings.skipWhitespacesBackward(line, len - 1); if (j >= 0 && line.charAt(j) == '}') { if (j > 0) j = 1 + Strings.skipWhitespacesBackward(line, j - 1); if (j == 0) //no non-space before } break; } } if (sb.length() > 0) sb.append('\n'); sb.append(line); } val = sb.toString(); } else { val = j <= k ? line.substring(j, k + 1): ""; } map.put(prefix != null ? prefix + key: key, val); } if (!prefixes.isEmpty()) log.warning(">>Ignored: unclosed nesting '{': "+prefixes.size()); } /** * Reads a property list (key and element pairs) from the input stream, * by specifying the charset. */ public final static void load(Map map, InputStream sm, String charset) throws IOException { load(map, sm, charset, false); } /** Reads a property list (key and element pairs) from the input stream, * by detecting correct charset. * * @param caseInsensitive whether the key used to access the map * is case-insensitive. If true, all keys are converted to lower cases. */ public final static void load(Map map, InputStream sm, boolean caseInsensitive) throws IOException { load(map, sm, null, caseInsensitive); } /** Reads a property list (key and element pairs) from the input stream, * by detecting correct charset. */ public final static void load(Map map, InputStream sm) throws IOException { load(map, sm, null, false); } /** * Parses a string into a map. * * <p>For example, if the following string is parsed:<br/> * a12=12,b3,c6=abc=125,x=y * * <p>Then, a map with the following content is returned:<br/> * ("a12", "12"), ("b3", null), ("c6", "abc=125"), ("x", "y") * * <p>If = is omitted, it is considered as a key with the null value. * If you want to consider it as the value, use * {@link #parse(Map, String, char, char, boolean)} instead. * Actually, this is the same as parse(map, src, separator, quote, false); * * <p>Notice: only the first = after separator is meaningful, * so you don't have to escape the following =. * * <p>Beside specifying the quote character, you could use back slash * quote a single character (as Java does). * * @param map the map to put parsed results to; null to create a * new hash map * @param src the string to parse * @param separator the separator, e.g., ' ' or ','. * @param quote the quote character to surrounding value, e.g., * name = 'value'. If (char)0, no quotation is recognized. * Notice: if value is an expression, it is better to specify (char)0 * because expression might contain strings. * @return the map being generated * * @exception IllegalSyntaxException if syntax errors * @see CollectionsX#parse * @see #toString(Map, char, char) */ public static final Map
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -