package com.ximple.eofms.util;
|
|
import java.util.Map;
|
import java.util.HashMap;
|
import java.util.Set;
|
import java.util.ArrayList;
|
import java.util.Iterator;
|
import java.util.Collection;
|
import java.util.Locale;
|
import java.util.regex.Pattern;
|
import java.util.regex.Matcher;
|
import java.nio.charset.Charset;
|
import java.nio.charset.CharsetEncoder;
|
import java.nio.charset.CharacterCodingException;
|
import java.nio.CharBuffer;
|
import java.io.UnsupportedEncodingException;
|
import java.net.URLEncoder;
|
import java.lang.reflect.Array;
|
import java.text.BreakIterator;
|
|
public abstract class StringUtils
|
{
|
public static String ENCODING_US_ASCII = "US-ASCII";
|
public static String ENCODING_ISO_8859_1 = "ISO-8859-1";
|
public static String ENCODING_ISO_8859_2 = "ISO-8859-2";
|
public static String ENCODING_ISO_8859_5 = "ISO-8859-5";
|
public static String ENCODING_UTF_8 = "UTF-8";
|
public static String ENCODING_UTF_16BE = "UTF-16BE";
|
public static String ENCODING_UTF_16LE = "UTF-16LE";
|
public static String ENCODING_UTF_16 = "UTF-16";
|
|
public static Charset CHARSET_US_ASCII = Charset.forName(StringUtils.ENCODING_US_ASCII);
|
|
public static final Pattern BBCODE_COLOR = Pattern.compile("\\[color\\s*=\\s*([#\\w]*)\\s*\\]", Pattern.CASE_INSENSITIVE);
|
public static final Pattern BBCODE_SIZE = Pattern.compile("\\[size\\s*=\\s*([+\\-]?[0-9]*)\\s*\\]", Pattern.CASE_INSENSITIVE);
|
public static final Pattern BBCODE_URL_SHORT = Pattern.compile("\\[url\\]\\s*([^\\s]*)\\s*\\[\\/url\\]", Pattern.CASE_INSENSITIVE);
|
public static final Pattern BBCODE_URL_LONG = Pattern.compile("\\[url=([^\\[]*)\\]([^\\[]*)\\[/url\\]", Pattern.CASE_INSENSITIVE);
|
public static final Pattern BBCODE_IMG = Pattern.compile("\\[img\\]\\s*([^\\s]*)\\s*\\[\\/img\\]", Pattern.CASE_INSENSITIVE);
|
public static final Pattern BBCODE_QUOTE_LONG = Pattern.compile("\\[quote=([^\\]]+\\]*)\\]", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
|
public static final Pattern BBCODE_BAREURL = Pattern.compile("(?:[^\"'=>\\]]|^)((?:http|ftp)s?://(?:%[\\p{Digit}A-Fa-f][\\p{Digit}A-Fa-f]|[\\-_\\.!~*';\\|/?:@#&=\\+$,\\p{Alnum}])+)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
|
|
private static final Map<Character, String> AGGRESSIVE_HTML_ENCODE_MAP = new HashMap<Character, String>();
|
private static final Map<Character, String> DEFENSIVE_HTML_ENCODE_MAP = new HashMap<Character, String>();
|
private static final Map<Character, String> XML_ENCODE_MAP = new HashMap<Character, String>();
|
private static final Map<Character, String> STRING_ENCODE_MAP = new HashMap<Character, String>();
|
private static final Map<Character, String> SQL_ENCODE_MAP = new HashMap<Character, String>();
|
private static final Map<Character, String> LATEX_ENCODE_MAP = new HashMap<Character, String>();
|
|
private static final Map<String, Character> HTML_DECODE_MAP = new HashMap<String, Character>();
|
|
private static final HtmlEncoderFallbackHandler HTML_ENCODER_FALLBACK = new HtmlEncoderFallbackHandler();
|
|
static
|
{
|
// Html encoding mapping according to the HTML 4.0 spec
|
// http://www.w3.org/TR/REC-html40/sgml/entities.html
|
|
// Special characters for HTML
|
AGGRESSIVE_HTML_ENCODE_MAP.put('\u0026',"&");
|
AGGRESSIVE_HTML_ENCODE_MAP.put('\u003C',"<");
|
AGGRESSIVE_HTML_ENCODE_MAP.put('\u003E',">");
|
AGGRESSIVE_HTML_ENCODE_MAP.put('\u0022',""");
|
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u0152',"Œ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u0153',"œ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u0160',"Š");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u0161',"š");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u0178',"Ÿ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u02C6',"ˆ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u02DC',"˜");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2002'," ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2003'," ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2009'," ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u200C',"‌");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u200D',"‍");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u200E',"‎");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u200F',"‏");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2013',"–");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2014',"—");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2018',"‘");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2019',"’");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u201A',"‚");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u201C',"“");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u201D',"”");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u201E',"„");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2020',"†");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2021',"‡");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2030',"‰");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2039',"‹");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u203A',"›");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u20AC',"€");
|
|
// Character entity references for ISO 8859-1 characters
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00A0'," ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00A1',"¡");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00A2',"¢");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00A3',"£");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00A4',"¤");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00A5',"¥");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00A6',"¦");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00A7',"§");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00A8',"¨");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00A9',"©");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00AA',"ª");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00AB',"«");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00AC',"¬");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00AD',"­");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00AE',"®");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00AF',"¯");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00B0',"°");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00B1',"±");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00B2',"²");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00B3',"³");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00B4',"´");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00B5',"µ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00B6',"¶");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00B7',"·");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00B8',"¸");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00B9',"¹");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00BA',"º");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00BB',"»");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00BC',"¼");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00BD',"½");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00BE',"¾");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00BF',"¿");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00C0',"À");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00C1',"Á");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00C2',"Â");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00C3',"Ã");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00C4',"Ä");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00C5',"Å");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00C6',"Æ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00C7',"Ç");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00C8',"È");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00C9',"É");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00CA',"Ê");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00CB',"Ë");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00CC',"Ì");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00CD',"Í");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00CE',"Î");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00CF',"Ï");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00D0',"Ð");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00D1',"Ñ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00D2',"Ò");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00D3',"Ó");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00D4',"Ô");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00D5',"Õ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00D6',"Ö");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00D7',"×");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00D8',"Ø");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00D9',"Ù");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00DA',"Ú");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00DB',"Û");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00DC',"Ü");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00DD',"Ý");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00DE',"Þ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00DF',"ß");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00E0',"à");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00E1',"á");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00E2',"â");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00E3',"ã");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00E4',"ä");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00E5',"å");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00E6',"æ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00E7',"ç");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00E8',"è");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00E9',"é");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00EA',"ê");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00EB',"ë");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00EC',"ì");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00ED',"í");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00EE',"î");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00EF',"ï");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00F0',"ð");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00F1',"ñ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00F2',"ò");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00F3',"ó");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00F4',"ô");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00F5',"õ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00F6',"ö");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00F7',"÷");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00F8',"ø");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00F9',"ù");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00FA',"ú");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00FB',"û");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00FC',"ü");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00FD',"ý");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00FE',"þ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u00FF',"ÿ");
|
|
// Mathematical, Greek and Symbolic characters for HTML
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u0192',"ƒ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u0391',"Α");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u0392',"Β");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u0393',"Γ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u0394',"Δ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u0395',"Ε");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u0396',"Ζ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u0397',"Η");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u0398',"Θ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u0399',"Ι");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u039A',"Κ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u039B',"Λ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u039C',"Μ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u039D',"Ν");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u039E',"Ξ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u039F',"Ο");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03A0',"Π");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03A1',"Ρ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03A3',"Σ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03A4',"Τ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03A5',"Υ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03A6',"Φ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03A7',"Χ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03A8',"Ψ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03A9',"Ω");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03B1',"α");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03B2',"β");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03B3',"γ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03B4',"δ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03B5',"ε");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03B6',"ζ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03B7',"η");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03B8',"θ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03B9',"ι");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03BA',"κ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03BB',"λ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03BC',"μ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03BD',"ν");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03BE',"ξ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03BF',"ο");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03C0',"π");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03C1',"ρ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03C2',"ς");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03C3',"σ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03C4',"τ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03C5',"υ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03C6',"φ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03C7',"χ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03C8',"ψ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03C9',"ω");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03D1',"ϑ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03D2',"ϒ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u03D6',"ϖ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2022',"•");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2026',"…");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2032',"′");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2033',"″");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u203E',"‾");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2044',"⁄");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2118',"℘");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2111',"ℑ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u211C',"ℜ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2122',"™");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2135',"ℵ");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2190',"←");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2191',"↑");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2192',"→");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2193',"↓");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2194',"↔");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u21B5',"↵");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u21D0',"⇐");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u21D1',"⇑");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u21D2',"⇒");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u21D3',"⇓");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u21D4',"⇔");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2200',"∀");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2202',"∂");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2203',"∃");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2205',"∅");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2207',"∇");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2208',"∈");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2209',"∉");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u220B',"∋");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u220F',"∏");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2211',"∑");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2212',"−");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2217',"∗");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u221A',"√");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u221D',"∝");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u221E',"∞");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2220',"∠");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2227',"∧");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2228',"∨");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2229',"∩");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u222A',"∪");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u222B',"∫");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2234',"∴");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u223C',"∼");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2245',"≅");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2248',"≈");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2260',"≠");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2261',"≡");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2264',"≤");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2265',"≥");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2282',"⊂");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2283',"⊃");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2284',"⊄");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2286',"⊆");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2287',"⊇");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2295',"⊕");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2297',"⊗");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u22A5',"⊥");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u22C5',"⋅");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2308',"⌈");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2309',"⌉");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u230A',"⌊");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u230B',"⌋");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2329',"⟨");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u232A',"⟩");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u25CA',"◊");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2660',"♠");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2663',"♣");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2665',"♥");
|
DEFENSIVE_HTML_ENCODE_MAP.put('\u2666',"♦");
|
|
Set<Map.Entry<Character, String>> aggresive_entries = AGGRESSIVE_HTML_ENCODE_MAP.entrySet();
|
for (Map.Entry<Character, String> entry : aggresive_entries)
|
{
|
HTML_DECODE_MAP.put(entry.getValue(), entry.getKey());
|
}
|
|
Set<Map.Entry<Character, String>> defensive_entries = DEFENSIVE_HTML_ENCODE_MAP.entrySet();
|
for (Map.Entry<Character, String> entry : defensive_entries)
|
{
|
HTML_DECODE_MAP.put(entry.getValue(), entry.getKey());
|
}
|
|
XML_ENCODE_MAP.put('\u0026',"&");
|
XML_ENCODE_MAP.put('\'',"'");
|
XML_ENCODE_MAP.put('\u0022',""");
|
XML_ENCODE_MAP.put('\u003C',"<");
|
XML_ENCODE_MAP.put('\u003E',">");
|
|
SQL_ENCODE_MAP.put('\'',"''");
|
|
STRING_ENCODE_MAP.put('\\',"\\\\");
|
STRING_ENCODE_MAP.put('\n',"\\n");
|
STRING_ENCODE_MAP.put('\r',"\\r");
|
STRING_ENCODE_MAP.put('\t',"\\t");
|
STRING_ENCODE_MAP.put('"',"\\\"");
|
|
LATEX_ENCODE_MAP.put('\\',"\\\\");
|
LATEX_ENCODE_MAP.put('#',"\\#");
|
LATEX_ENCODE_MAP.put('$',"\\$");
|
LATEX_ENCODE_MAP.put('%',"\\%");
|
LATEX_ENCODE_MAP.put('&',"\\&");
|
LATEX_ENCODE_MAP.put('~',"\\~");
|
LATEX_ENCODE_MAP.put('_',"\\_");
|
LATEX_ENCODE_MAP.put('^',"\\^");
|
LATEX_ENCODE_MAP.put('{',"\\{");
|
LATEX_ENCODE_MAP.put('}',"\\}");
|
LATEX_ENCODE_MAP.put('\u00A1',"!'");
|
LATEX_ENCODE_MAP.put('\u00BF',"?'");
|
LATEX_ENCODE_MAP.put('\u00C0',"\\`{A}");
|
LATEX_ENCODE_MAP.put('\u00C1',"\\'{A}");
|
LATEX_ENCODE_MAP.put('\u00C2',"\\^{A}");
|
LATEX_ENCODE_MAP.put('\u00C3',"\\H{A}");
|
LATEX_ENCODE_MAP.put('\u00C4',"\\\"{A}");
|
LATEX_ENCODE_MAP.put('\u00C5',"\\AA");
|
LATEX_ENCODE_MAP.put('\u00C6',"\\AE");
|
LATEX_ENCODE_MAP.put('\u00C7',"\\c{C}");
|
LATEX_ENCODE_MAP.put('\u00C8',"\\`{E}");
|
LATEX_ENCODE_MAP.put('\u00C9',"\\'{E}");
|
LATEX_ENCODE_MAP.put('\u00CA',"\\^{E}");
|
LATEX_ENCODE_MAP.put('\u00CB',"\\\"{E}");
|
LATEX_ENCODE_MAP.put('\u00CC',"\\`{I}");
|
LATEX_ENCODE_MAP.put('\u00CD',"\\'{I}");
|
LATEX_ENCODE_MAP.put('\u00CE',"\\^{I}");
|
LATEX_ENCODE_MAP.put('\u00CF',"\\\"{I}");
|
// todo \u00D0
|
LATEX_ENCODE_MAP.put('\u00D1',"\\H{N}");
|
LATEX_ENCODE_MAP.put('\u00D2',"\\`{O}");
|
LATEX_ENCODE_MAP.put('\u00D3',"\\'{O}");
|
LATEX_ENCODE_MAP.put('\u00D4',"\\^{O}");
|
LATEX_ENCODE_MAP.put('\u00D5',"\\H{O}");
|
LATEX_ENCODE_MAP.put('\u00D6',"\\\"{O}");
|
// todo \u00D7
|
LATEX_ENCODE_MAP.put('\u00D8',"\\O");
|
LATEX_ENCODE_MAP.put('\u00D9',"\\`{U}");
|
LATEX_ENCODE_MAP.put('\u00DA',"\\'{U}");
|
LATEX_ENCODE_MAP.put('\u00DB',"\\^{U}");
|
LATEX_ENCODE_MAP.put('\u00DC',"\\\"{U}");
|
LATEX_ENCODE_MAP.put('\u00DD',"\\'{Y}");
|
// todo \u00DE
|
LATEX_ENCODE_MAP.put('\u00DF',"\\ss");
|
LATEX_ENCODE_MAP.put('\u00E0',"\\`{a}");
|
LATEX_ENCODE_MAP.put('\u00E1',"\\'{a}");
|
LATEX_ENCODE_MAP.put('\u00E2',"\\^{a}");
|
LATEX_ENCODE_MAP.put('\u00E3',"\\H{a}");
|
LATEX_ENCODE_MAP.put('\u00E4',"\\\"{a}");
|
LATEX_ENCODE_MAP.put('\u00E5',"\\aa");
|
LATEX_ENCODE_MAP.put('\u00E6',"\\ae");
|
LATEX_ENCODE_MAP.put('\u00E7',"\\c{c}");
|
LATEX_ENCODE_MAP.put('\u00E8',"\\`{e}");
|
LATEX_ENCODE_MAP.put('\u00E9',"\\'{e}");
|
LATEX_ENCODE_MAP.put('\u00EA',"\\^{e}");
|
LATEX_ENCODE_MAP.put('\u00EB',"\\\"{e}");
|
LATEX_ENCODE_MAP.put('\u00EC',"\\`{i}");
|
LATEX_ENCODE_MAP.put('\u00ED',"\\'{i}");
|
LATEX_ENCODE_MAP.put('\u00EE',"\\^{i}");
|
LATEX_ENCODE_MAP.put('\u00EF',"\\\"{i}");
|
// todo \u00F0
|
LATEX_ENCODE_MAP.put('\u00F1',"\\H{n}");
|
LATEX_ENCODE_MAP.put('\u00F2',"\\`{o}");
|
LATEX_ENCODE_MAP.put('\u00F3',"\\'{o}");
|
LATEX_ENCODE_MAP.put('\u00F4',"\\^{o}");
|
LATEX_ENCODE_MAP.put('\u00F5',"\\H{o}");
|
LATEX_ENCODE_MAP.put('\u00F6',"\\\"{o}");
|
// todo \u00F7
|
LATEX_ENCODE_MAP.put('\u00F8',"\\o");
|
LATEX_ENCODE_MAP.put('\u00F9',"\\`{u}");
|
LATEX_ENCODE_MAP.put('\u00FA',"\\'{u}");
|
LATEX_ENCODE_MAP.put('\u00FB',"\\^{u}");
|
LATEX_ENCODE_MAP.put('\u00FC',"\\\"{u}");
|
LATEX_ENCODE_MAP.put('\u00FD',"\\'{y}");
|
// todo \u00FE
|
LATEX_ENCODE_MAP.put('\u00FF',"\\\"{y}");
|
}
|
|
/**
|
* Transforms a provided <code>String</code> object into a new string,
|
* containing only valid characters for a java class name.
|
*
|
* @param name The string that has to be transformed into a valid class
|
* name.
|
* @return The encoded <code>String</code> object.
|
* @see #encodeUrl(String)
|
* @see #encodeHtml(String)
|
* @see #encodeXml(String)
|
* @see #encodeSql(String)
|
* @see #encodeLatex(String)
|
* @see #encodeRegexp(String)
|
* @since 1.0
|
*/
|
public static String encodeClassname(String name)
|
{
|
if (null == name)
|
{
|
return null;
|
}
|
|
Pattern pattern = Pattern.compile("[^\\w]");
|
Matcher matcher = pattern.matcher(name);
|
|
return matcher.replaceAll("_");
|
}
|
|
private static boolean needsUrlEncoding(String source)
|
{
|
if (null == source)
|
{
|
return false;
|
}
|
|
// check if the string needs encoding first since
|
// the URLEncoder always allocates a StringBuffer, even when the
|
// string is returned as-is
|
boolean encode = false;
|
char ch;
|
for (int i = 0; i < source.length(); i++)
|
{
|
ch = source.charAt(i);
|
|
if (ch >= 'a' && ch <= 'z' ||
|
ch >= 'A' && ch <= 'Z' ||
|
ch >= '0' && ch <= '9' ||
|
ch == '-' || ch == '_' || ch == '.' || ch == '*')
|
{
|
continue;
|
}
|
|
encode = true;
|
break;
|
}
|
|
return encode;
|
}
|
|
/**
|
* Transforms a provided <code>String</code> object into a new string,
|
* containing only valid URL characters.
|
*
|
* @param source The string that has to be transformed into a valid URL
|
* string.
|
* @return The encoded <code>String</code> object.
|
* @see #encodeClassname(String)
|
* @see #encodeUrlValue(String)
|
* @see #encodeHtml(String)
|
* @see #encodeXml(String)
|
* @see #encodeSql(String)
|
* @see #encodeLatex(String)
|
* @see #encodeRegexp(String)
|
* @since 1.0
|
*/
|
public static String encodeUrl(String source)
|
{
|
if (!needsUrlEncoding(source))
|
{
|
return source;
|
}
|
|
try
|
{
|
return URLEncoder.encode(source, ENCODING_ISO_8859_1);
|
}
|
///CLOVER:OFF
|
catch (UnsupportedEncodingException e)
|
{
|
// this should never happen, ISO-8859-1 is a standard encoding
|
throw new RuntimeException(e);
|
}
|
///CLOVER:ON
|
}
|
|
/**
|
* Transforms a provided <code>String</code> object into a new string,
|
* only pure US Ascii strings are preserved and URL encoded in a regular
|
* way. Strings with characters from other encodings will be encoded in a
|
* RIFE-specific manner to allow international data to passed along the
|
* query string.
|
*
|
* @param source The string that has to be transformed into a valid URL
|
* parameter string.
|
* @return The encoded <code>String</code> object.
|
* @see #decodeUrlValue(String)
|
* @see #encodeClassname(String)
|
* @see #encodeUrl(String)
|
* @see #encodeHtml(String)
|
* @see #encodeXml(String)
|
* @see #encodeSql(String)
|
* @see #encodeLatex(String)
|
* @see #encodeRegexp(String)
|
* @since 1.0
|
*/
|
public static String encodeUrlValue(String source)
|
{
|
if (!needsUrlEncoding(source))
|
{
|
return source;
|
}
|
|
// check if the string is valid US-ASCII encoding
|
boolean valid = true;
|
CharsetEncoder encoder = CHARSET_US_ASCII.newEncoder();
|
try
|
{
|
encoder.encode(CharBuffer.wrap(source));
|
}
|
catch (CharacterCodingException e)
|
{
|
valid = false;
|
}
|
|
try
|
{
|
// if it is valid US-ASCII, use the regular URL encoding method
|
if (valid)
|
{
|
return URLEncoder.encode(source, ENCODING_US_ASCII);
|
}
|
// otherwise, base-64 encode the UTF-8 bytes and mark the string
|
// as being encoded in a special way
|
else
|
{
|
StringBuilder encoded = new StringBuilder("%02%02");
|
String base64 = Base64.encodeToString(source.getBytes(ENCODING_UTF_8), false);
|
String base64_urlsafe = replace(base64, "=", "%3D");
|
encoded.append(base64_urlsafe);
|
|
return encoded.toString();
|
}
|
}
|
///CLOVER:OFF
|
catch (UnsupportedEncodingException e)
|
{
|
// this should never happen, ISO-8859-1 is a standard encoding
|
throw new RuntimeException(e);
|
}
|
///CLOVER:ON
|
}
|
|
/**
|
* Decodes a <code>String</code> that has been encoded in a RIFE-specific
|
* manner for URL usage.. Before calling this method, you should first
|
* verify if the value needs decoding by using the
|
* <code>doesUrlValueNeedDecoding(String)</code> method.
|
*
|
* @param source the value that has been encoded for URL usage in a
|
* RIFE-specific way
|
* @return The decoded <code>String</code> object.
|
* @see #encodeUrlValue(String)
|
* @see #doesUrlValueNeedDecoding(String)
|
* @since 1.0
|
*/
|
public static String decodeUrlValue(String source)
|
{
|
try
|
{
|
byte[] decoded = Base64.decode(source.substring(2));
|
if (null == decoded)
|
{
|
return null;
|
}
|
else
|
{
|
return new String(decoded, StringUtils.ENCODING_UTF_8);
|
}
|
}
|
///CLOVER:OFF
|
catch (UnsupportedEncodingException e)
|
{
|
// this should never happen, UTF-8 is a standard encoding
|
throw new RuntimeException(e);
|
}
|
///CLOVER:ON
|
}
|
|
/**
|
* Checks if a <code>String</code> is encoded in a RIFE-specific manner
|
* for URL usage.
|
*
|
* @param source the value that might have been encoded for URL usage in a
|
* RIFE-specific way
|
* @return <code>true</code> if the value is encoded in the RIFE-specific
|
* format; and
|
* <p><code>false</code> otherwise
|
* @see #encodeUrlValue(String)
|
* @see #decodeUrlValue(String)
|
* @since 1.0
|
*/
|
public static boolean doesUrlValueNeedDecoding(String source)
|
{
|
if (source != null &&
|
source.length() > 2 &&
|
source.startsWith("\u0002\u0002"))
|
{
|
return true;
|
}
|
|
return false;
|
}
|
|
private static boolean needsHtmlEncoding(String source, boolean defensive)
|
{
|
if (null == source)
|
{
|
return false;
|
}
|
|
boolean encode = false;
|
char ch;
|
for (int i = 0; i < source.length(); i++)
|
{
|
ch = source.charAt(i);
|
|
if ((defensive || (ch != '\u0022' && ch != '\u0026' && ch != '\u003C' && ch != '\u003E')) &&
|
ch < '\u00A0')
|
{
|
continue;
|
}
|
|
encode = true;
|
break;
|
}
|
|
return encode;
|
}
|
|
/**
|
*
|
* @since 1.6
|
*/
|
public static String decodeHtml(String source)
|
{
|
if (null == source ||
|
0 == source.length())
|
{
|
return source;
|
}
|
|
int current_index = 0;
|
int delimiter_start_index = 0;
|
int delimiter_end_index = 0;
|
|
StringBuilder result = null;
|
|
while (current_index <= source.length())
|
{
|
delimiter_start_index = source.indexOf('&', current_index);
|
if (delimiter_start_index != -1)
|
{
|
delimiter_end_index = source.indexOf(';', delimiter_start_index + 1);
|
if (delimiter_end_index != -1)
|
{
|
// ensure that the string builder is setup correctly
|
if (null == result)
|
{
|
result = new StringBuilder();
|
}
|
|
// add the text that leads up to this match
|
if (delimiter_start_index > current_index)
|
{
|
result.append(source.substring(current_index, delimiter_start_index));
|
}
|
|
// add the decoded entity
|
String entity = source.substring(delimiter_start_index, delimiter_end_index + 1);
|
|
current_index = delimiter_end_index + 1;
|
|
// try to decoded numeric entities
|
if (entity.charAt(1) == '#')
|
{
|
int start = 2;
|
int radix = 10;
|
// check if the number is hexadecimal
|
if (entity.charAt(2) == 'X' || entity.charAt(2) == 'x')
|
{
|
start++;
|
radix = 16;
|
}
|
try
|
{
|
Character c = new Character((char)Integer.parseInt(entity.substring(start, entity.length() - 1), radix));
|
result.append(c);
|
}
|
// when the number of the entity can't be parsed, add the entity as-is
|
catch (NumberFormatException e)
|
{
|
result.append(entity);
|
}
|
}
|
else
|
{
|
// try to decode the entity as a literal
|
Character decoded = HTML_DECODE_MAP.get(entity);
|
if (decoded != null)
|
{
|
result.append(decoded);
|
}
|
// if there was no match, add the entity as-is
|
else
|
{
|
result.append(entity);
|
}
|
}
|
}
|
else
|
{
|
break;
|
}
|
}
|
else
|
{
|
break;
|
}
|
}
|
|
if (null == result)
|
{
|
return source;
|
}
|
else if (current_index < source.length())
|
{
|
result.append(source.substring(current_index));
|
}
|
|
return result.toString();
|
}
|
|
/**
|
* Transforms a provided <code>String</code> object into a new string,
|
* containing only valid Html characters.
|
*
|
* @param source The string that has to be transformed into a valid Html
|
* string.
|
* @return The encoded <code>String</code> object.
|
* @see #encodeClassname(String)
|
* @see #encodeUrl(String)
|
* @see #encodeUrlValue(String)
|
* @see #encodeXml(String)
|
* @see #encodeSql(String)
|
* @see #encodeString(String)
|
* @see #encodeLatex(String)
|
* @see #encodeRegexp(String)
|
* @since 1.0
|
*/
|
public static String encodeHtml(String source)
|
{
|
if (needsHtmlEncoding(source, false))
|
{
|
return encode(source, HTML_ENCODER_FALLBACK, AGGRESSIVE_HTML_ENCODE_MAP, DEFENSIVE_HTML_ENCODE_MAP);
|
}
|
return source;
|
}
|
|
/**
|
* Transforms a provided <code>String</code> object into a new string,
|
* containing as much as possible Html characters. It is safe to already
|
* feed existing Html to this method since &, < and > will not
|
* be encoded.
|
*
|
* @param source The string that has to be transformed into a valid Html
|
* string.
|
* @return The encoded <code>String</code> object.
|
* @see #encodeClassname(String)
|
* @see #encodeUrl(String)
|
* @see #encodeUrlValue(String)
|
* @see #encodeXml(String)
|
* @see #encodeSql(String)
|
* @see #encodeString(String)
|
* @see #encodeLatex(String)
|
* @see #encodeRegexp(String)
|
* @since 1.0
|
*/
|
public static String encodeHtmlDefensive(String source)
|
{
|
if (needsHtmlEncoding(source, true))
|
{
|
return encode(source, null, DEFENSIVE_HTML_ENCODE_MAP);
|
}
|
return source;
|
}
|
|
/**
|
* Transforms a provided <code>String</code> object into a new string,
|
* containing only valid XML characters.
|
*
|
* @param source The string that has to be transformed into a valid XML
|
* string.
|
* @return The encoded <code>String</code> object.
|
* @see #encodeClassname(String)
|
* @see #encodeUrl(String)
|
* @see #encodeUrlValue(String)
|
* @see #encodeHtml(String)
|
* @see #encodeSql(String)
|
* @see #encodeString(String)
|
* @see #encodeLatex(String)
|
* @see #encodeRegexp(String)
|
* @since 1.0
|
*/
|
public static String encodeXml(String source)
|
{
|
return encode(source, null, XML_ENCODE_MAP);
|
}
|
|
/**
|
* Transforms a provided <code>String</code> object into a new string,
|
* containing only valid <code>String</code> characters.
|
*
|
* @param source The string that has to be transformed into a valid
|
* sequence of <code>String</code> characters.
|
* @return The encoded <code>String</code> object.
|
* @see #encodeClassname(String)
|
* @see #encodeUrl(String)
|
* @see #encodeUrlValue(String)
|
* @see #encodeHtml(String)
|
* @see #encodeXml(String)
|
* @see #encodeSql(String)
|
* @see #encodeLatex(String)
|
* @see #encodeRegexp(String)
|
* @since 1.0
|
*/
|
public static String encodeString(String source)
|
{
|
return encode(source, null, STRING_ENCODE_MAP);
|
}
|
|
/**
|
* Transforms a provided <code>String</code> object into a series of
|
* unicode escape codes.
|
*
|
* @param source The string that has to be transformed into a valid
|
* sequence of unicode escape codes
|
* @return The encoded <code>String</code> object.
|
* @see #encodeClassname(String)
|
* @see #encodeUrl(String)
|
* @see #encodeUrlValue(String)
|
* @see #encodeHtml(String)
|
* @see #encodeXml(String)
|
* @see #encodeSql(String)
|
* @see #encodeLatex(String)
|
* @see #encodeRegexp(String)
|
* @since 1.0
|
*/
|
public static String encodeUnicode(String source)
|
{
|
if (null == source)
|
{
|
return null;
|
}
|
|
StringBuilder encoded = new StringBuilder();
|
String hexstring = null;
|
for (int i = 0; i < source.length(); i++)
|
{
|
hexstring = Integer.toHexString((int)source.charAt(i)).toUpperCase();
|
encoded.append("\\u");
|
// fill with zeros
|
for (int j = hexstring.length(); j < 4; j++)
|
{
|
encoded.append("0");
|
}
|
encoded.append(hexstring);
|
}
|
|
return encoded.toString();
|
}
|
|
/**
|
* Transforms a provided <code>String</code> object into a new string,
|
* containing only valid Sql characters.
|
*
|
* @param source The string that has to be transformed into a valid Sql
|
* string.
|
* @return The encoded <code>String</code> object.
|
* @see #encodeClassname(String)
|
* @see #encodeUrl(String)
|
* @see #encodeUrlValue(String)
|
* @see #encodeHtml(String)
|
* @see #encodeXml(String)
|
* @see #encodeString(String)
|
* @see #encodeLatex(String)
|
* @see #encodeRegexp(String)
|
* @since 1.0
|
*/
|
public static String encodeSql(String source)
|
{
|
return encode(source, null, SQL_ENCODE_MAP);
|
}
|
|
/**
|
* Transforms a provided <code>String</code> object into a new string,
|
* containing only valid LaTeX characters.
|
*
|
* @param source The string that has to be transformed into a valid LaTeX
|
* string.
|
* @return The encoded <code>String</code> object.
|
* @see #encodeClassname(String)
|
* @see #encodeUrl(String)
|
* @see #encodeUrlValue(String)
|
* @see #encodeHtml(String)
|
* @see #encodeXml(String)
|
* @see #encodeSql(String)
|
* @see #encodeString(String)
|
* @see #encodeRegexp(String)
|
* @since 1.0
|
*/
|
public static String encodeLatex(String source)
|
{
|
if (null == source)
|
{
|
return null;
|
}
|
|
source = encode(source, null, LATEX_ENCODE_MAP);
|
source = StringUtils.replace(source, "latex", "\\LaTeX", false);
|
|
return source;
|
}
|
|
/**
|
* Transforms a provided <code>String</code> object into a new string,
|
* using the mapping that are provided through the supplied encoding
|
* table.
|
*
|
* @param source The string that has to be transformed into a valid
|
* string, using the mappings that are provided through the supplied
|
* encoding table.
|
* @param encodingTables A <code>Map</code> object containing the mappings
|
* to transform characters into valid entities. The keys of this map
|
* should be <code>Character</code> objects and the values
|
* <code>String</code> objects.
|
* @return The encoded <code>String</code> object.
|
* @since 1.0
|
*/
|
private static String encode(String source, EncoderFallbackHandler fallbackHandler, Map<Character, String>... encodingTables)
|
{
|
if (null == source)
|
{
|
return null;
|
}
|
|
if (null == encodingTables ||
|
0 == encodingTables.length)
|
{
|
return source;
|
}
|
|
StringBuilder encoded_string = null;
|
char[] string_to_encode_array = source.toCharArray();
|
int last_match = -1;
|
|
for (int i = 0; i < string_to_encode_array.length; i++)
|
{
|
char char_to_encode = string_to_encode_array[i];
|
for (Map<Character, String> encoding_table : encodingTables)
|
{
|
if (encoding_table.containsKey(char_to_encode))
|
{
|
encoded_string = prepareEncodedString(source, encoded_string, i, last_match, string_to_encode_array);
|
|
encoded_string.append(encoding_table.get(char_to_encode));
|
last_match = i;
|
}
|
}
|
|
if (fallbackHandler != null &&
|
last_match < i &&
|
fallbackHandler.hasFallback(char_to_encode))
|
{
|
encoded_string = prepareEncodedString(source, encoded_string, i, last_match, string_to_encode_array);
|
|
fallbackHandler.appendFallback(encoded_string, char_to_encode);
|
last_match = i;
|
}
|
}
|
|
if (null == encoded_string)
|
{
|
return source;
|
}
|
else
|
{
|
int difference = string_to_encode_array.length-(last_match+1);
|
if (difference > 0)
|
{
|
encoded_string.append(string_to_encode_array, last_match+1, difference);
|
}
|
return encoded_string.toString();
|
}
|
}
|
|
private static StringBuilder prepareEncodedString(String source, StringBuilder encodedString, int i, int lastMatch, char[] stringToEncodeArray)
|
{
|
if (null == encodedString)
|
{
|
encodedString = new StringBuilder(source.length());
|
}
|
|
int difference = i - (lastMatch + 1);
|
if (difference > 0)
|
{
|
encodedString.append(stringToEncodeArray, lastMatch + 1, difference);
|
}
|
|
return encodedString;
|
}
|
|
private static interface EncoderFallbackHandler
|
{
|
abstract boolean hasFallback(char character);
|
abstract void appendFallback(StringBuilder encodedBuffer, char character);
|
}
|
|
private static class HtmlEncoderFallbackHandler implements EncoderFallbackHandler
|
{
|
private final static String PREFIX = "&#";
|
private final static String SUFFIX = ";";
|
|
public boolean hasFallback(char character)
|
{
|
if (character < '\u00A0')
|
{
|
return false;
|
}
|
|
return true;
|
}
|
|
public void appendFallback(StringBuilder encodedBuffer, char character)
|
{
|
encodedBuffer.append(PREFIX);
|
encodedBuffer.append((int)character);
|
encodedBuffer.append(SUFFIX);
|
}
|
}
|
|
/**
|
* Transforms a provided <code>String</code> object into a literal that can
|
* be included into a regular expression {@link Pattern} as-is. None of the
|
* regular expression escapes in the string will be functional anymore.
|
*
|
* @param source The string that has to be escaped as a literal
|
* @return The encoded <code>String</code> object.
|
* @see #encodeClassname(String)
|
* @see #encodeUrl(String)
|
* @see #encodeUrlValue(String)
|
* @see #encodeHtml(String)
|
* @see #encodeXml(String)
|
* @see #encodeSql(String)
|
* @see #encodeString(String)
|
* @see #encodeLatex(String)
|
* @since 1.3
|
*/
|
public static String encodeRegexp(String source)
|
{
|
int regexp_quote_start = source.indexOf("\\E");
|
if (-1 == regexp_quote_start)
|
{
|
return "\\Q" + source + "\\E";
|
}
|
|
StringBuilder buffer = new StringBuilder(source.length() * 2);
|
buffer.append("\\Q");
|
|
regexp_quote_start = 0;
|
|
int current = 0;
|
while (-1 == (regexp_quote_start = source.indexOf("\\E", current)))
|
{
|
buffer.append(source.substring(current, regexp_quote_start));
|
current = regexp_quote_start + 2;
|
buffer.append("\\E\\\\E\\Q");
|
}
|
|
buffer.append(source.substring(current, source.length()));
|
buffer.append("\\E");
|
|
return buffer.toString();
|
}
|
|
/**
|
* Counts the number of times a substring occures in a provided string in
|
* a case-sensitive manner.
|
*
|
* @param source The <code>String</code> object that will be searched in.
|
* @param substring The string whose occurances will we counted.
|
* @return An <code>int</code> value containing the number of occurances
|
* of the substring.
|
* @since 1.0
|
*/
|
public static int count(String source, String substring)
|
{
|
return count(source, substring, true);
|
}
|
|
/**
|
* Counts the number of times a substring occures in a provided string.
|
*
|
* @param source The <code>String</code> object that will be searched in.
|
* @param substring The string whose occurances will we counted.
|
* @param matchCase A <code>boolean</code> indicating if the match is
|
* going to be performed in a case-sensitive manner or not.
|
* @return An <code>int</code> value containing the number of occurances
|
* of the substring.
|
* @since 1.0
|
*/
|
public static int count(String source, String substring, boolean matchCase)
|
{
|
if (null == source)
|
{
|
return 0;
|
}
|
|
if (null == substring)
|
{
|
return 0;
|
}
|
|
int current_index = 0;
|
int substring_index = 0;
|
int count = 0;
|
|
if (!matchCase)
|
{
|
source = source.toLowerCase();
|
substring = substring.toLowerCase();
|
}
|
|
while (current_index < source.length()-1)
|
{
|
substring_index = source.indexOf(substring, current_index);
|
|
if (-1 == substring_index)
|
{
|
break;
|
}
|
else
|
{
|
current_index = substring_index + substring.length();
|
count++;
|
}
|
}
|
|
return count;
|
}
|
|
/**
|
* Splits a string into different parts, using a seperator string to
|
* detect the seperation boundaries in a case-sensitive manner. The
|
* seperator will not be included in the list of parts.
|
*
|
* @param source The string that will be split into parts.
|
* @param seperator The seperator string that will be used to determine
|
* the parts.
|
* @return An <code>ArrayList</code> containing the parts as
|
* <code>String</code> objects.
|
* @since 1.0
|
*/
|
public static ArrayList<String> split(String source, String seperator)
|
{
|
return split(source, seperator, true);
|
}
|
|
/**
|
* Splits a string into different parts, using a seperator string to
|
* detect the seperation boundaries. The seperator will not be included in
|
* the list of parts.
|
*
|
* @param source The string that will be split into parts.
|
* @param seperator The seperator string that will be used to determine
|
* the parts.
|
* @param matchCase A <code>boolean</code> indicating if the match is
|
* going to be performed in a case-sensitive manner or not.
|
* @return An <code>ArrayList</code> containing the parts as
|
* <code>String</code> objects.
|
* @since 1.0
|
*/
|
public static ArrayList<String> split(String source, String seperator, boolean matchCase)
|
{
|
ArrayList<String> substrings = new ArrayList<String>();
|
|
if (null == source)
|
{
|
return substrings;
|
}
|
|
if (null == seperator)
|
{
|
substrings.add(source);
|
return substrings;
|
}
|
|
int current_index = 0;
|
int delimiter_index = 0;
|
String element = null;
|
|
String source_lookup_reference = null;
|
if (!matchCase)
|
{
|
source_lookup_reference = source.toLowerCase();
|
seperator = seperator.toLowerCase();
|
}
|
else
|
{
|
source_lookup_reference = source;
|
}
|
|
while (current_index <= source_lookup_reference.length())
|
{
|
delimiter_index = source_lookup_reference.indexOf(seperator, current_index);
|
|
if (-1 == delimiter_index)
|
{
|
element = new String(source.substring(current_index, source.length()));
|
substrings.add(element);
|
current_index = source.length() + 1;
|
}
|
else
|
{
|
element = new String(source.substring(current_index, delimiter_index));
|
substrings.add(element);
|
current_index = delimiter_index + seperator.length();
|
}
|
}
|
|
return substrings;
|
}
|
|
/**
|
* Splits a string into different parts, using a seperator string to
|
* detect the seperation boundaries in a case-sensitive manner. The
|
* seperator will not be included in the parts array.
|
*
|
* @param source The string that will be split into parts.
|
* @param seperator The seperator string that will be used to determine
|
* the parts.
|
* @return A <code>String[]</code> array containing the seperated parts.
|
* @since 1.0
|
*/
|
public static String[] splitToArray(String source, String seperator)
|
{
|
return splitToArray(source, seperator, true);
|
}
|
|
/**
|
* Splits a string into different parts, using a seperator string to
|
* detect the seperation boundaries. The seperator will not be included in
|
* the parts array.
|
*
|
* @param source The string that will be split into parts.
|
* @param seperator The seperator string that will be used to determine
|
* the parts.
|
* @param matchCase A <code>boolean</code> indicating if the match is
|
* going to be performed in a case-sensitive manner or not.
|
* @return A <code>String[]</code> array containing the seperated parts.
|
* @since 1.0
|
*/
|
public static String[] splitToArray(String source, String seperator, boolean matchCase)
|
{
|
ArrayList<String> substrings = split(source, seperator, matchCase);
|
String[] substrings_array = new String[substrings.size()];
|
substrings_array = substrings.toArray(substrings_array);
|
|
return substrings_array;
|
}
|
|
/**
|
* Splits a string into integers, using a seperator string to detect the
|
* seperation boundaries in a case-sensitive manner. If a part couldn't be
|
* converted to an integer, it will be omitted from the resulting array.
|
*
|
* @param source The string that will be split into integers.
|
* @param seperator The seperator string that will be used to determine
|
* the parts.
|
* @return An <code>int[]</code> array containing the seperated parts.
|
* @since 1.0
|
*/
|
public static int[] splitToIntArray(String source, String seperator)
|
{
|
return splitToIntArray(source, seperator, true);
|
}
|
|
/**
|
* Splits a string into integers, using a seperator string to detect the
|
* seperation boundaries. If a part couldn't be converted to an integer,
|
* it will be omitted from the resulting array.
|
*
|
* @param source The string that will be split into integers.
|
* @param seperator The seperator string that will be used to determine
|
* the parts.
|
* @param matchCase A <code>boolean</code> indicating if the match is
|
* going to be performed in a case-sensitive manner or not.
|
* @return An <code>int[]</code> array containing the seperated parts.
|
* @since 1.0
|
*/
|
public static int[] splitToIntArray(String source, String seperator, boolean matchCase)
|
{
|
ArrayList<String> string_parts = split(source, seperator, matchCase);
|
int number_of_valid_parts = 0;
|
|
for (String string_part : string_parts)
|
{
|
try
|
{
|
Integer.parseInt(string_part);
|
number_of_valid_parts++;
|
}
|
catch (NumberFormatException e)
|
{
|
// just continue
|
}
|
}
|
|
int[] string_parts_int = (int[]) Array.newInstance(int.class, number_of_valid_parts);
|
int added_parts = 0;
|
|
for (String string_part : string_parts)
|
{
|
try
|
{
|
string_parts_int[added_parts] = Integer.parseInt(string_part);
|
added_parts++;
|
}
|
catch (NumberFormatException e)
|
{
|
// just continue
|
}
|
}
|
|
return string_parts_int;
|
}
|
|
/**
|
* Splits a string into bytes, using a seperator string to detect the
|
* seperation boundaries in a case-sensitive manner. If a part couldn't be
|
* converted to a <code>byte</code>, it will be omitted from the resulting
|
* array.
|
*
|
* @param source The string that will be split into bytes.
|
* @param seperator The seperator string that will be used to determine
|
* the parts.
|
* @return A <code>byte[]</code> array containing the bytes.
|
* @since 1.0
|
*/
|
public static byte[] splitToByteArray(String source, String seperator)
|
{
|
return splitToByteArray(source, seperator, true);
|
}
|
|
/**
|
* Splits a string into bytes, using a seperator string to detect the
|
* seperation boundaries. If a part couldn't be converted to a
|
* <code>byte</code>, it will be omitted from the resulting array.
|
*
|
* @param source The string that will be split into bytes.
|
* @param seperator The seperator string that will be used to determine
|
* the parts.
|
* @param matchCase A <code>boolean</code> indicating if the match is
|
* going to be performed in a case-sensitive manner or not.
|
* @return A <code>byte[]</code> array containing the bytes.
|
* @since 1.0
|
*/
|
public static byte[] splitToByteArray(String source, String seperator, boolean matchCase)
|
{
|
ArrayList<String> string_parts = split(source, seperator, matchCase);
|
int number_of_valid_parts = 0;
|
for (String string_part : string_parts)
|
{
|
try
|
{
|
Byte.parseByte(string_part);
|
number_of_valid_parts++;
|
}
|
catch (NumberFormatException e)
|
{
|
// just continue
|
}
|
}
|
|
byte[] string_parts_byte = (byte[])Array.newInstance(byte.class, number_of_valid_parts);
|
int added_parts = 0;
|
for (String string_part : string_parts)
|
{
|
try
|
{
|
string_parts_byte[added_parts] = Byte.parseByte(string_part);
|
added_parts++;
|
}
|
catch (NumberFormatException e)
|
{
|
// just continue
|
}
|
}
|
|
return string_parts_byte;
|
}
|
|
/**
|
* Removes all occurances of a string from the front of another string in
|
* a case-sensitive manner.
|
*
|
* @param source The string in which the matching will be done.
|
* @param stringToStrip The string that will be stripped from the front.
|
* @return A new <code>String</code> containing the stripped result.
|
* @since 1.0
|
*/
|
public static String stripFromFront(String source, String stringToStrip)
|
{
|
return stripFromFront(source, stringToStrip, true);
|
}
|
|
/**
|
* Removes all occurances of a string from the front of another string.
|
*
|
* @param source The string in which the matching will be done.
|
* @param stringToStrip The string that will be stripped from the front.
|
* @param matchCase A <code>boolean</code> indicating if the match is
|
* going to be performed in a case-sensitive manner or not.
|
* @return A new <code>String</code> containing the stripping result.
|
* @since 1.0
|
*/
|
public static String stripFromFront(String source, String stringToStrip, boolean matchCase)
|
{
|
if (null == source)
|
{
|
return null;
|
}
|
|
if (null == stringToStrip)
|
{
|
return source;
|
}
|
|
int strip_length = stringToStrip.length();
|
int new_index = 0;
|
int last_index = 0;
|
|
String source_lookup_reference = null;
|
if (!matchCase)
|
{
|
source_lookup_reference = source.toLowerCase();
|
stringToStrip = stringToStrip.toLowerCase();
|
}
|
else
|
{
|
source_lookup_reference = source;
|
}
|
|
new_index = source_lookup_reference.indexOf(stringToStrip);
|
if (0 == new_index)
|
{
|
do
|
{
|
last_index = new_index;
|
new_index = source_lookup_reference.indexOf(stringToStrip, new_index+strip_length);
|
}
|
while (new_index != -1 &&
|
new_index == last_index+strip_length);
|
|
return source.substring(last_index+strip_length);
|
}
|
else
|
{
|
return source;
|
}
|
}
|
|
/**
|
* Removes all occurances of a string from the end of another string in a
|
* case-sensitive manner.
|
*
|
* @param source The string in which the matching will be done.
|
* @param stringToStrip The string that will be stripped from the end.
|
* @return A new <code>String</code> containing the stripped result.
|
* @since 1.0
|
*/
|
public static String stripFromEnd(String source, String stringToStrip)
|
{
|
return stripFromEnd(source, stringToStrip, true);
|
}
|
|
/**
|
* Removes all occurances of a string from the end of another string.
|
*
|
* @param source The string in which the matching will be done.
|
* @param stringToStrip The string that will be stripped from the end.
|
* @param matchCase A <code>boolean</code> indicating if the match is
|
* going to be performed in a case-sensitive manner or not.
|
* @return A new <code>String</code> containing the stripped result.
|
* @since 1.0
|
*/
|
public static String stripFromEnd(String source, String stringToStrip, boolean matchCase)
|
{
|
if (null == source)
|
{
|
return null;
|
}
|
|
if (null == stringToStrip)
|
{
|
return source;
|
}
|
|
int strip_length = stringToStrip.length();
|
int new_index = 0;
|
int last_index = 0;
|
|
String source_lookup_reference = null;
|
if (!matchCase)
|
{
|
source_lookup_reference = source.toLowerCase();
|
stringToStrip = stringToStrip.toLowerCase();
|
}
|
else
|
{
|
source_lookup_reference = source;
|
}
|
|
new_index = source_lookup_reference.lastIndexOf(stringToStrip);
|
if (new_index != -1 &&
|
source.length() == new_index+strip_length)
|
{
|
do
|
{
|
last_index = new_index;
|
new_index = source_lookup_reference.lastIndexOf(stringToStrip, last_index-1);
|
}
|
while (new_index != -1 &&
|
new_index == last_index-strip_length);
|
|
return source.substring(0, last_index);
|
}
|
else
|
{
|
return source;
|
}
|
}
|
|
/**
|
* Searches for a string within a specified string in a case-sensitive
|
* manner and replaces every match with another string.
|
*
|
* @param source The string in which the matching parts will be replaced.
|
* @param stringToReplace The string that will be searched for.
|
* @param replacementString The string that will replace each matching
|
* part.
|
* @return A new <code>String</code> object containing the replacement
|
* result.
|
* @since 1.0
|
*/
|
public static String replace(String source, String stringToReplace, String replacementString)
|
{
|
return replace(source, stringToReplace, replacementString, true);
|
}
|
|
/**
|
* Searches for a string within a specified string and replaces every
|
* match with another string.
|
*
|
* @param source The string in which the matching parts will be replaced.
|
* @param stringToReplace The string that will be searched for.
|
* @param replacementString The string that will replace each matching
|
* part.
|
* @param matchCase A <code>boolean</code> indicating if the match is
|
* going to be performed in a case-sensitive manner or not.
|
* @return A new <code>String</code> object containing the replacement
|
* result.
|
* @since 1.0
|
*/
|
public static String replace(String source, String stringToReplace, String replacementString, boolean matchCase)
|
{
|
if (null == source)
|
{
|
return null;
|
}
|
|
if (null == stringToReplace)
|
{
|
return source;
|
}
|
|
if (null == replacementString)
|
{
|
return source;
|
}
|
|
Iterator<String> string_parts = split(source, stringToReplace, matchCase).iterator();
|
StringBuilder new_string = new StringBuilder();
|
|
while (string_parts.hasNext())
|
{
|
String string_part = string_parts.next();
|
new_string.append(string_part);
|
if (string_parts.hasNext())
|
{
|
new_string.append(replacementString);
|
}
|
}
|
|
return new_string.toString();
|
}
|
|
/**
|
* Creates a new string that contains the provided string a number of
|
* times.
|
*
|
* @param source The string that will be repeated.
|
* @param count The number of times that the string will be repeated.
|
* @return A new <code>String</code> object containing the repeated
|
* concatenation result.
|
* @since 1.0
|
*/
|
public static String repeat(String source, int count)
|
{
|
if (null == source)
|
{
|
return null;
|
}
|
|
StringBuilder new_string = new StringBuilder();
|
while (count > 0)
|
{
|
new_string.append(source);
|
count --;
|
}
|
|
return new_string.toString();
|
}
|
|
/**
|
* Creates a new array of <code>String</code> objects, containing the
|
* elements of a supplied <code>Iterator</code>.
|
*
|
* @param iterator The iterator containing the elements to create the
|
* array with.
|
* @return The new <code>String</code> array.
|
* @since 1.0
|
*/
|
public static String[] toStringArray(Iterator<String> iterator)
|
{
|
if (null == iterator)
|
{
|
return new String[0];
|
}
|
|
ArrayList<String> strings = new ArrayList<String>();
|
|
while (iterator.hasNext())
|
{
|
strings.add(iterator.next());
|
}
|
|
String[] string_array = new String[strings.size()];
|
strings.toArray(string_array);
|
|
return string_array;
|
}
|
|
/**
|
* Creates a new <code>ArrayList</code>, containing the elements of a
|
* supplied array of <code>String</code> objects.
|
*
|
* @param stringArray The array of <code>String</code> objects that have
|
* to be converted.
|
* @return The new <code>ArrayList</code> with the elements of the
|
* <code>String</code> array.
|
* @since 1.0
|
*/
|
public static ArrayList<String> toArrayList(String[] stringArray)
|
{
|
ArrayList<String> strings = new ArrayList<String>();
|
|
if (null == stringArray)
|
{
|
return strings;
|
}
|
|
for (String element : stringArray)
|
{
|
strings.add(element);
|
}
|
|
return strings;
|
}
|
|
/**
|
* Creates a new <code>String</code> object, containing the elements of a
|
* supplied <code>Collection</code> of <code>String</code> objects joined
|
* by a given seperator.
|
*
|
* @param collection The <code>Collection</code> containing the elements
|
* to join.
|
* @param seperator The seperator used to join the string elements.
|
* @return A new <code>String</code> with the join result.
|
* @since 1.0
|
*/
|
public static String join(Collection collection, String seperator)
|
{
|
if (null == collection)
|
{
|
return null;
|
}
|
|
if (null == seperator)
|
{
|
seperator = "";
|
}
|
|
if (0 == collection.size())
|
{
|
return "";
|
}
|
else
|
{
|
StringBuilder result = new StringBuilder();
|
for (Object element : collection)
|
{
|
result.append(String.valueOf(element));
|
result.append(seperator);
|
}
|
|
result.setLength(result.length()-seperator.length());
|
return result.toString();
|
}
|
}
|
|
/**
|
* Creates a new <code>String</code> object, containing the elements of a
|
* supplied array, joined by a given seperator.
|
*
|
* @param array The object array containing the elements to join.
|
* @param seperator The seperator used to join the string elements.
|
* @return A new <code>String</code> with the join result.
|
* @since 1.0
|
*/
|
public static String join(Object[] array, String seperator)
|
{
|
return join(array, seperator, null, false);
|
}
|
|
/**
|
* Creates a new <code>String</code> object, containing the elements of a
|
* supplied array, joined by a given seperator.
|
*
|
* @param array The object array containing the elements to join.
|
* @param seperator The seperator used to join the string elements.
|
* @param delimiter The delimiter used to surround the string elements.
|
* @return A new <code>String</code> with the join result.
|
* @since 1.0
|
*/
|
public static String join(Object[] array, String seperator, String delimiter)
|
{
|
return join(array, seperator, delimiter, false);
|
}
|
|
/**
|
* Creates a new <code>String</code> object, containing the elements of a
|
* supplied array, joined by a given seperator.
|
*
|
* @param array The object array containing the elements to join.
|
* @param seperator The seperator used to join the string elements.
|
* @param delimiter The delimiter used to surround the string elements.
|
* @param encodeStrings Indicates whether the characters of the string
|
* representation of the Array values should be encoded.
|
* @return A new <code>String</code> with the join result.
|
* @since 1.0
|
*/
|
public static String join(Object[] array, String seperator, String delimiter, boolean encodeStrings)
|
{
|
if (null == array)
|
{
|
return null;
|
}
|
|
if (null == seperator)
|
{
|
seperator = "";
|
}
|
|
if (null == delimiter)
|
{
|
delimiter = "";
|
}
|
|
if (0 == array.length)
|
{
|
return "";
|
}
|
else
|
{
|
int current_index = 0;
|
String array_value = null;
|
StringBuilder result = new StringBuilder();
|
while (current_index < array.length - 1)
|
{
|
if (null == array[current_index])
|
{
|
result.append("null");
|
}
|
else
|
{
|
array_value = String.valueOf(array[current_index]);
|
if (encodeStrings)
|
{
|
array_value = encodeString(array_value);
|
}
|
result.append(delimiter);
|
result.append(array_value);
|
result.append(delimiter);
|
}
|
result.append(seperator);
|
current_index++;
|
}
|
|
if (null == array[current_index])
|
{
|
result.append("null");
|
}
|
else
|
{
|
array_value = String.valueOf(array[current_index]);
|
if (encodeStrings)
|
{
|
array_value = encodeString(array_value);
|
}
|
result.append(delimiter);
|
result.append(array_value);
|
result.append(delimiter);
|
}
|
return result.toString();
|
}
|
}
|
|
/**
|
* Creates a new <code>String</code> object, containing the elements of a
|
* supplied array, joined by a given seperator.
|
*
|
* @param array The boolean array containing the values to join.
|
* @param seperator The seperator used to join the string elements.
|
* @return A new <code>String</code> with the join result.
|
* @since 1.0
|
*/
|
public static String join(boolean[] array, String seperator)
|
{
|
if (null == array)
|
{
|
return null;
|
}
|
|
if (null == seperator)
|
{
|
seperator = "";
|
}
|
|
if (0 == array.length)
|
{
|
return "";
|
}
|
else
|
{
|
int current_index = 0;
|
String result = "";
|
while (current_index < array.length - 1)
|
{
|
result = result + array[current_index] + seperator;
|
current_index++;
|
}
|
|
result = result + array[current_index];
|
return result;
|
}
|
}
|
|
/**
|
* Creates a new <code>String</code> object, containing the elements of a
|
* supplied array, joined by a given seperator.
|
*
|
* @param array The byte array containing the values to join.
|
* @param seperator The seperator used to join the string elements.
|
* @return A new <code>String</code> with the join result.
|
* @since 1.0
|
*/
|
public static String join(byte[] array, String seperator)
|
{
|
if (null == array)
|
{
|
return null;
|
}
|
|
if (null == seperator)
|
{
|
seperator = "";
|
}
|
|
if (0 == array.length)
|
{
|
return "";
|
}
|
else
|
{
|
int current_index = 0;
|
String result = "";
|
while (current_index < array.length - 1)
|
{
|
result = result + array[current_index] + seperator;
|
current_index++;
|
}
|
|
result = result + array[current_index];
|
return result;
|
}
|
}
|
|
/**
|
* Creates a new <code>String</code> object, containing the elements of a
|
* supplied array, joined by a given seperator.
|
*
|
* @param array The double array containing the values to join.
|
* @param seperator The seperator used to join the string elements.
|
* @return A new <code>String</code> with the join result.
|
* @since 1.0
|
*/
|
public static String join(double[] array, String seperator)
|
{
|
if (null == array)
|
{
|
return null;
|
}
|
|
if (null == seperator)
|
{
|
seperator = "";
|
}
|
|
if (0 == array.length)
|
{
|
return "";
|
}
|
else
|
{
|
int current_index = 0;
|
String result = "";
|
while (current_index < array.length - 1)
|
{
|
result = result + array[current_index] + seperator;
|
current_index++;
|
}
|
|
result = result + array[current_index];
|
return result;
|
}
|
}
|
|
/**
|
* Creates a new <code>String</code> object, containing the elements of a
|
* supplied array, joined by a given seperator.
|
*
|
* @param array The float array containing the values to join.
|
* @param seperator The seperator used to join the string elements.
|
* @return A new <code>String</code> with the join result.
|
* @since 1.0
|
*/
|
public static String join(float[] array, String seperator)
|
{
|
if (null == array)
|
{
|
return null;
|
}
|
|
if (null == seperator)
|
{
|
seperator = "";
|
}
|
|
if (0 == array.length)
|
{
|
return "";
|
}
|
else
|
{
|
int current_index = 0;
|
String result = "";
|
while (current_index < array.length - 1)
|
{
|
result = result + array[current_index] + seperator;
|
current_index++;
|
}
|
|
result = result + array[current_index];
|
return result;
|
}
|
}
|
|
/**
|
* Creates a new <code>String</code> object, containing the elements of a
|
* supplied array, joined by a given seperator.
|
*
|
* @param array The integer array containing the values to join.
|
* @param seperator The seperator used to join the string elements.
|
* @return A new <code>String</code> with the join result.
|
* @since 1.0
|
*/
|
public static String join(int[] array, String seperator)
|
{
|
if (null == array)
|
{
|
return null;
|
}
|
|
if (null == seperator)
|
{
|
seperator = "";
|
}
|
|
if (0 == array.length)
|
{
|
return "";
|
}
|
else
|
{
|
int current_index = 0;
|
String result = "";
|
while (current_index < array.length - 1)
|
{
|
result = result + array[current_index] + seperator;
|
current_index++;
|
}
|
|
result = result + array[current_index];
|
return result;
|
}
|
}
|
|
/**
|
* Creates a new <code>String</code> object, containing the elements of a
|
* supplied array, joined by a given seperator.
|
*
|
* @param array The long array containing the values to join.
|
* @param seperator The seperator used to join the string elements.
|
* @return A new <code>String</code> with the join result.
|
* @since 1.0
|
*/
|
public static String join(long[] array, String seperator)
|
{
|
if (null == array)
|
{
|
return null;
|
}
|
|
if (null == seperator)
|
{
|
seperator = "";
|
}
|
|
if (0 == array.length)
|
{
|
return "";
|
}
|
else
|
{
|
int current_index = 0;
|
String result = "";
|
while (current_index < array.length - 1)
|
{
|
result = result + array[current_index] + seperator;
|
current_index++;
|
}
|
|
result = result + array[current_index];
|
return result;
|
}
|
}
|
|
/**
|
* Creates a new <code>String</code> object, containing the elements of a
|
* supplied array, joined by a given seperator.
|
*
|
* @param array The short array containing the values to join.
|
* @param seperator The seperator used to join the string elements.
|
* @return A new <code>String</code> with the join result.
|
* @since 1.0
|
*/
|
public static String join(short[] array, String seperator)
|
{
|
if (null == array)
|
{
|
return null;
|
}
|
|
if (null == seperator)
|
{
|
seperator = "";
|
}
|
|
if (0 == array.length)
|
{
|
return "";
|
}
|
else
|
{
|
int current_index = 0;
|
String result = "";
|
while (current_index < array.length - 1)
|
{
|
result = result + array[current_index] + seperator;
|
current_index++;
|
}
|
|
result = result + array[current_index];
|
return result;
|
}
|
}
|
|
/**
|
* Creates a new <code>String</code> object, containing the elements of a
|
* supplied array, joined by a given seperator.
|
*
|
* @param array The char array containing the values to join.
|
* @param seperator The seperator used to join the string elements.
|
* @return A new <code>String</code> with the join result.
|
* @since 1.0
|
*/
|
public static String join(char[] array, String seperator)
|
{
|
return join(array, seperator, null);
|
}
|
|
/**
|
* Creates a new <code>String</code> object, containing the elements of a
|
* supplied array, joined by a given seperator.
|
*
|
* @param array The char array containing the values to join.
|
* @param seperator The seperator used to join the string elements.
|
* @param delimiter The delimiter used to surround the string elements.
|
* @return A new <code>String</code> with the join result.
|
* @since 1.0
|
*/
|
public static String join(char[] array, String seperator, String delimiter)
|
{
|
if (null == array)
|
{
|
return null;
|
}
|
|
if (null == seperator)
|
{
|
seperator = "";
|
}
|
|
if (null == delimiter)
|
{
|
delimiter = "";
|
}
|
|
if (0 == array.length)
|
{
|
return "";
|
}
|
else
|
{
|
int current_index = 0;
|
StringBuilder result = new StringBuilder();
|
while (current_index < array.length - 1)
|
{
|
result.append(delimiter);
|
result.append(array[current_index]);
|
result.append(delimiter);
|
result.append(seperator);
|
current_index++;
|
}
|
|
result.append(delimiter);
|
result.append(String.valueOf(array[current_index]));
|
result.append(delimiter);
|
return result.toString();
|
}
|
}
|
|
/**
|
* Returns an array that contains all the occurances of a substring in a
|
* string in the correct order. The search will be performed in a
|
* case-sensitive manner.
|
*
|
* @param source The <code>String</code> object that will be searched in.
|
* @param substring The string whose occurances will we counted.
|
* @return An <code>int[]</code> array containing the indices of the
|
* substring.
|
* @since 1.0
|
*/
|
public static int[] indicesOf(String source, String substring)
|
{
|
return indicesOf(source, substring, true);
|
}
|
|
/**
|
* Returns an array that contains all the occurances of a substring in a
|
* string in the correct order.
|
*
|
* @param source The <code>String</code> object that will be searched in.
|
* @param substring The string whose occurances will we counted.
|
* @param matchCase A <code>boolean</code> indicating if the match is
|
* going to be performed in a case-sensitive manner or not.
|
* @return An <code>int[]</code> array containing the indices of the
|
* substring.
|
* @since 1.0
|
*/
|
public static int[] indicesOf(String source, String substring, boolean matchCase)
|
{
|
if (null == source ||
|
null == substring)
|
{
|
return new int[0];
|
}
|
|
String source_lookup_reference = null;
|
if (!matchCase)
|
{
|
source_lookup_reference = source.toLowerCase();
|
substring = substring.toLowerCase();
|
}
|
else
|
{
|
source_lookup_reference = source;
|
}
|
|
int current_index = 0;
|
int substring_index = 0;
|
int count = count(source_lookup_reference, substring);
|
int[] indices = new int[count];
|
int counter = 0;
|
|
while (current_index < source.length()-1)
|
{
|
substring_index = source_lookup_reference.indexOf(substring, current_index);
|
|
if (-1 == substring_index)
|
{
|
break;
|
}
|
else
|
{
|
current_index = substring_index + substring.length();
|
indices[counter] = substring_index;
|
counter++;
|
}
|
}
|
|
return indices;
|
}
|
|
/**
|
* Matches a collection of regular expressions against a string.
|
*
|
* @param value The <code>String</code> that will be checked.
|
* @param regexps The collection of regular expressions against which the
|
* match will be performed.
|
* @return The <code>Matcher</code> instance that corresponds to the
|
* <code>String</code> that returned a successful match; or
|
* <p><code>null</code> if no match could be found.
|
* @since 1.0
|
*/
|
public static Matcher getMatchingRegexp(String value, Collection<Pattern> regexps)
|
{
|
if (value != null &&
|
value.length() > 0 &&
|
regexps != null &&
|
regexps.size() > 0)
|
{
|
Matcher matcher = null;
|
for (Pattern regexp : regexps)
|
{
|
matcher = regexp.matcher(value);
|
if (matcher.matches())
|
{
|
return matcher;
|
}
|
}
|
}
|
|
return null;
|
}
|
|
/**
|
* Matches a collection of strings against a regular expression.
|
*
|
* @param values The <code>Collection</code> of <code>String</code>
|
* objects that will be checked.
|
* @param regexp The regular expression <code>Pattern</code> against which
|
* the matches will be performed.
|
* @return The <code>Matcher</code> instance that corresponds to the
|
* <code>String</code> that returned a successful match; or
|
* <p><code>null</code> if no match could be found.
|
* @since 1.0
|
*/
|
public static Matcher getRegexpMatch(Collection<String> values, Pattern regexp)
|
{
|
if (values != null &&
|
values.size() > 0 &&
|
regexp != null)
|
{
|
Matcher matcher = null;
|
for (String value : values)
|
{
|
matcher = regexp.matcher(value);
|
if (matcher.matches())
|
{
|
return matcher;
|
}
|
}
|
}
|
|
return null;
|
}
|
|
/**
|
* Checks if the name filters through an including and an excluding
|
* regular expression.
|
*
|
* @param name The <code>String</code> that will be filtered.
|
* @param included The regular expressions that needs to succeed
|
* @param excluded The regular expressions that needs to fail
|
* @return <code>true</code> if the name filtered through correctly; or
|
* <p><code>false</code> otherwise.
|
* @since 1.0
|
*/
|
public static boolean filter(String name, Pattern included, Pattern excluded)
|
{
|
Pattern[] included_array = null;
|
if (included != null)
|
{
|
included_array = new Pattern[] {included};
|
}
|
|
Pattern[] excluded_array = null;
|
if (excluded != null)
|
{
|
excluded_array = new Pattern[] {excluded};
|
}
|
|
return filter(name, included_array, excluded_array);
|
}
|
|
/**
|
* Checks if the name filters through a series of including and excluding
|
* regular expressions.
|
*
|
* @param name The <code>String</code> that will be filtered.
|
* @param included An array of regular expressions that need to succeed
|
* @param excluded An array of regular expressions that need to fail
|
* @return <code>true</code> if the name filtered through correctly; or
|
* <p><code>false</code> otherwise.
|
* @since 1.0
|
*/
|
public static boolean filter(String name, Pattern[] included, Pattern[] excluded)
|
{
|
if (null == name)
|
{
|
return false;
|
}
|
|
boolean accepted = false;
|
|
// retain only the includes
|
if (null == included)
|
{
|
accepted = true;
|
}
|
else
|
{
|
for (Pattern pattern : included)
|
{
|
if (pattern != null &&
|
pattern.matcher(name).matches())
|
{
|
accepted = true;
|
break;
|
}
|
}
|
}
|
|
// remove the excludes
|
if (accepted &&
|
excluded != null)
|
{
|
for (Pattern pattern : excluded)
|
{
|
if (pattern != null &&
|
pattern.matcher(name).matches())
|
{
|
accepted = false;
|
break;
|
}
|
}
|
}
|
|
return accepted;
|
}
|
|
/**
|
* Ensure that the first character of the provided string is upper case.
|
*
|
* @param source The <code>String</code> to capitalize.
|
* @return The capitalized <code>String</code>.
|
* @since 1.0
|
*/
|
public static String capitalize(String source)
|
{
|
if (source == null || source.length() == 0)
|
{
|
return source;
|
}
|
|
if (source.length() > 1 &&
|
Character.isUpperCase(source.charAt(0)))
|
{
|
return source;
|
}
|
|
char chars[] = source.toCharArray();
|
chars[0] = Character.toUpperCase(chars[0]);
|
return new String(chars);
|
}
|
|
/**
|
* Ensure that the first character of the provided string lower case.
|
*
|
* @param source The <code>String</code> to uncapitalize.
|
* @return The uncapitalized <code>String</code>.
|
* @since 1.5
|
*/
|
public static String uncapitalize(String source)
|
{
|
if (source == null || source.length() == 0)
|
{
|
return source;
|
}
|
|
if (source.length() > 1 &&
|
Character.isLowerCase(source.charAt(0)))
|
{
|
return source;
|
}
|
|
char chars[] = source.toCharArray();
|
chars[0] = Character.toLowerCase(chars[0]);
|
return new String(chars);
|
}
|
|
private static String convertUrl(String source, Pattern pattern, boolean shorten, boolean sanitize, boolean no_follow)
|
{
|
int max_length = 1024;
|
|
String result = source;
|
|
Matcher url_matcher = pattern.matcher(source);
|
boolean found = url_matcher.find();
|
if (found)
|
{
|
String visual_url = null;
|
String actual_url = null;
|
int last = 0;
|
StringBuilder sb = new StringBuilder();
|
do
|
{
|
actual_url = url_matcher.group(1);
|
if (url_matcher.groupCount() > 1)
|
{
|
visual_url = url_matcher.group(2);
|
}
|
else
|
{
|
visual_url = actual_url;
|
}
|
|
if (sanitize)
|
{
|
// defang javascript
|
actual_url = StringUtils.replace(actual_url, "javascript:", "");
|
|
// fill in http:// for URLs that don't begin with /
|
if ((actual_url.indexOf("://") == -1) &&
|
(!actual_url.startsWith("/")))
|
{
|
actual_url = "http://"+actual_url;
|
}
|
}
|
|
if (pattern.equals(BBCODE_BAREURL))
|
{
|
sb.append(source.substring(last, url_matcher.start(1)));
|
}
|
else
|
{
|
sb.append(source.substring(last, url_matcher.start(0)));
|
}
|
sb.append("<a href=\"");
|
sb.append(actual_url);
|
sb.append("\"");
|
if (actual_url.startsWith("http://") ||
|
actual_url.startsWith("https://"))
|
{
|
sb.append(" target=\"_blank\"");
|
}
|
if (no_follow)
|
{
|
sb.append(" rel=\"nofollow\"");
|
}
|
sb.append(">");
|
if (visual_url.length() <= max_length || !shorten)
|
{
|
sb.append(visual_url);
|
}
|
else
|
{
|
String ellipsis = "...";
|
int query_index = visual_url.indexOf("?");
|
|
// hack query string off
|
// keep '?'
|
if (query_index != -1)
|
{
|
visual_url = visual_url.substring(0, query_index + 1) + ellipsis;
|
}
|
|
if (visual_url.length() >= max_length)
|
{
|
int last_slash = visual_url.lastIndexOf("/");
|
int start_slash = visual_url.indexOf("/", visual_url.indexOf("://")+3);
|
|
if (last_slash != start_slash)
|
{
|
visual_url = visual_url.substring(0, start_slash + 1) + ellipsis + visual_url.substring(last_slash);
|
}
|
}
|
|
sb.append(visual_url);
|
}
|
sb.append("</a>");
|
|
if (pattern.equals(BBCODE_BAREURL))
|
{
|
last = url_matcher.end(1);
|
}
|
else
|
{
|
last = url_matcher.end(0);
|
}
|
|
found = url_matcher.find();
|
}
|
while (found);
|
|
sb.append(source.substring(last));
|
result = sb.toString();
|
}
|
|
return result;
|
}
|
|
private static String parseBBCode(String source, boolean shorten, boolean sanitize, boolean convert_bare, boolean no_follow)
|
{
|
String result = source;
|
|
result = StringUtils.replace(result, "[b]", "<b>", false);
|
result = StringUtils.replace(result, "[/b]", "</b>", false);
|
result = StringUtils.replace(result, "[u]", "<u>", false);
|
result = StringUtils.replace(result, "[/u]", "</u>", false);
|
result = StringUtils.replace(result, "[i]", "<i>", false);
|
result = StringUtils.replace(result, "[/i]", "</i>", false);
|
result = StringUtils.replace(result, "[pre]", "<pre>", false);
|
result = StringUtils.replace(result, "[/pre]", "</pre>", false);
|
|
String resultCopy = result;
|
String resultLowerCopy = result.toLowerCase();
|
StringBuilder buffer = new StringBuilder();
|
int startIndex;
|
int endIndex;
|
while (-1 != (startIndex = resultLowerCopy.indexOf("[*]")))
|
{
|
int begin = resultLowerCopy.indexOf("[list]", startIndex + 3);
|
int end = resultLowerCopy.indexOf("[/list]", startIndex + 3);
|
int next = resultLowerCopy.indexOf("[*]", startIndex + 3); // 3 == sizeof [*]
|
|
if (begin == -1)
|
{
|
begin = Integer.MAX_VALUE;
|
}
|
|
if (end == -1)
|
{
|
end = Integer.MAX_VALUE;
|
}
|
|
if (next == -1)
|
{
|
next = Integer.MAX_VALUE;
|
}
|
|
if (next < begin && next < end)
|
{
|
endIndex = next;
|
}
|
else if (begin < next && begin < end)
|
{
|
endIndex = begin;
|
}
|
else if (end < next && end < begin)
|
{
|
endIndex = end;
|
}
|
else
|
{
|
endIndex = resultLowerCopy.length();
|
}
|
|
buffer
|
.append(resultCopy.substring(0, startIndex))
|
.append("<li>")
|
.append(resultCopy.substring(startIndex + 3, endIndex)) // 3 == sizeof [*]
|
.append("</li>");
|
|
resultCopy = resultCopy.substring(endIndex);
|
resultLowerCopy = resultLowerCopy.substring(endIndex);
|
}
|
buffer.append(resultCopy.substring(0));
|
|
result = buffer.toString();
|
|
result = StringUtils.replace(result, "[list]", "<ul>", false);
|
result = StringUtils.replace(result, "[/list]", "</ul>", false);
|
|
Matcher color_matcher = BBCODE_COLOR.matcher(result);
|
result = color_matcher.replaceAll("<font color=\"$1\">");
|
result = StringUtils.replace(result, "[/color]", "</font>", false);
|
|
Matcher size_matcher = BBCODE_SIZE.matcher(result);
|
result = size_matcher.replaceAll("<font size=\"$1\">");
|
result = StringUtils.replace(result, "[/size]", "</font>", false);
|
|
result = convertUrl(result, BBCODE_URL_SHORT, shorten, sanitize, no_follow);
|
result = convertUrl(result, BBCODE_URL_LONG, shorten, sanitize, no_follow);
|
|
if (convert_bare)
|
{
|
result = convertUrl(result, BBCODE_BAREURL, shorten, sanitize, no_follow);
|
}
|
|
Matcher img_matcher = BBCODE_IMG.matcher(result);
|
result = img_matcher.replaceAll("<div class=\"bbcode_img\"><img src=\"$1\" border=\"0\" alt=\"\" /></div>");
|
|
Matcher quote_matcher_long = BBCODE_QUOTE_LONG.matcher(result);
|
result = quote_matcher_long.replaceAll("<div class=\"quoteaccount\">$1:</div><div class=\"quotebody\">");
|
result = StringUtils.replace(result, "[quote]", "<div class=\"quotebody\">", false);
|
result = StringUtils.replace(result, "[/quote]", "</div>", false);
|
|
result = StringUtils.replace(result, "\r\n", "<br />\r");
|
result = StringUtils.replace(result, "\n", "<br />\n");
|
result = StringUtils.replace(result, "\r", "\r\n");
|
|
// remove the BR that could be added due to code formatting ppl
|
// use to format lists
|
result = StringUtils.replace(result, "ul><br />\r\n", "ul>\r\n");
|
result = StringUtils.replace(result, "ul><br />\n", "ul>\n");
|
|
return result;
|
}
|
|
/**
|
* Converts a <code>String</code> to a <code>boolean</code> value.
|
*
|
* @param value The <code>String</code> to convert.
|
* @return The corresponding <code>boolean</code> value.
|
* @since 1.0
|
*/
|
public static boolean convertToBoolean(String value)
|
{
|
if (null == value)
|
{
|
return false;
|
}
|
|
if (value.equals("1") ||
|
value.equalsIgnoreCase("t") ||
|
value.equalsIgnoreCase("true") ||
|
value.equalsIgnoreCase("y") ||
|
value.equalsIgnoreCase("yes") ||
|
value.equalsIgnoreCase("on"))
|
{
|
return true;
|
}
|
|
return false;
|
}
|
|
/**
|
* Converts all tabs on a line to spaces according to the provided tab
|
* width.
|
*
|
* @param line The line whose tabs have to be converted.
|
* @param tabWidth The tab width.
|
* @return A new <code>String</code> object containing the line with the
|
* replaced tabs.
|
* @since 1.0
|
*/
|
public static String convertTabsToSpaces(String line, int tabWidth)
|
{
|
StringBuilder result = new StringBuilder();
|
int tab_index = -1;
|
int last_tab_index = 0;
|
int added_chars = 0;
|
int tab_size;
|
while ((tab_index = line.indexOf("\t", last_tab_index)) != -1)
|
{
|
tab_size = tabWidth-((tab_index+added_chars)%tabWidth);
|
if (0 == tab_size)
|
{
|
tab_size = tabWidth;
|
}
|
added_chars += tab_size-1;
|
result.append(line.substring(last_tab_index, tab_index));
|
result.append(StringUtils.repeat(" ", tab_size));
|
last_tab_index = tab_index+1;
|
}
|
if (0 == last_tab_index)
|
{
|
return line;
|
}
|
else
|
{
|
result.append(line.substring(last_tab_index));
|
}
|
|
return result.toString();
|
}
|
|
/**
|
* Ensures that all whitespace is removed from a <code>String</code>.
|
* <p>It also works with a <code>null</code> argument.
|
*
|
* @param source The <code>String</code> to trim.
|
* @return The trimmed <code>String</code>.
|
* @since 1.0
|
*/
|
public static String trim(String source)
|
{
|
if (source == null || source.length() == 0)
|
{
|
return source;
|
}
|
|
return source.trim();
|
}
|
|
/**
|
* Reformats a string where lines that are longer than <tt>width</tt>
|
* are split apart at the earliest wordbreak or at maxLength, whichever is
|
* sooner. If the width specified is less than 5 or greater than the input
|
* Strings length the string will be returned as is.
|
* <p>
|
* Please note that this method can be lossy - trailing spaces on wrapped
|
* lines may be trimmed.
|
*
|
* @param input the String to reformat.
|
* @param width the maximum length of any one line.
|
* @return a new String with reformatted as needed.
|
*/
|
public static String wordWrap(String input, int width, Locale locale)
|
{
|
// handle invalid input
|
if (input == null)
|
{
|
return "";
|
}
|
else if (width < 5)
|
{
|
return input;
|
}
|
else if (width >= input.length())
|
{
|
return input;
|
}
|
|
// default locale
|
if (locale == null)
|
{
|
locale = Locale.US;
|
}
|
|
StringBuilder buffer = new StringBuilder(input.length());
|
int current_index = 0;
|
int delimiter_index = 0;
|
String seperator = "\n";
|
String line;
|
|
// go over the input string and jump from line to line
|
while (current_index <= input.length())
|
{
|
// look for the next linebreak
|
delimiter_index = input.indexOf(seperator, current_index);
|
|
// get the line that corresponds to it
|
if (-1 == delimiter_index)
|
{
|
line = new String(input.substring(current_index, input.length()));
|
current_index = input.length() + 1;
|
}
|
else
|
{
|
line = new String(input.substring(current_index, delimiter_index));
|
current_index = delimiter_index + seperator.length();
|
}
|
|
// handle the wrapping of the line
|
BreakIterator breaks = BreakIterator.getLineInstance(locale);
|
breaks.setText(line);
|
|
int line_start = 0;
|
int start = breaks.first();
|
int end = breaks.next();
|
while (end != BreakIterator.DONE)
|
{
|
// check if the width has been exceeded
|
if (end - 1 - line_start >= width)
|
{
|
boolean break_line = true;
|
|
// first check if the last characters were spaces,
|
// if they were and by removing them the width is not
|
// exceeded, just continue
|
if (Character.isWhitespace(line.charAt(end - 1)))
|
{
|
for (int j = end - 1; j >= 0; j--)
|
{
|
if (!Character.isWhitespace(line.charAt(j)))
|
{
|
if (j - line_start < width)
|
{
|
break_line = false;
|
}
|
|
break;
|
}
|
}
|
}
|
|
if (break_line)
|
{
|
String line_breaked = line.substring(line_start, start);
|
// this can happen with trailing whitespace
|
if (line_breaked.length() > width)
|
{
|
line_breaked = line_breaked.substring(0, width);
|
}
|
buffer.append(line_breaked);
|
|
buffer.append("\n");
|
|
line_start = start;
|
}
|
}
|
|
start = end;
|
end = breaks.next();
|
}
|
|
if (line_start < line.length())
|
{
|
buffer.append(line.substring(line_start));
|
}
|
|
if (delimiter_index != -1)
|
{
|
buffer.append("\n");
|
}
|
}
|
|
return buffer.toString();
|
}
|
}
|