Java tutorial
/* * Copyright (c) 2000-2004 Netspective Communications LLC. All rights reserved. * * Netspective Communications LLC ("Netspective") permits redistribution, modification and use of this file in source * and binary form ("The Software") under the Netspective Source License ("NSL" or "The License"). The following * conditions are provided as a summary of the NSL but the NSL remains the canonical license and must be accepted * before using The Software. Any use of The Software indicates agreement with the NSL. * * 1. Each copy or derived work of The Software must preserve the copyright notice and this notice unmodified. * * 2. Redistribution of The Software is allowed in object code form only (as Java .class files or a .jar file * containing the .class files) and only as part of an application that uses The Software as part of its primary * functionality. No distribution of the package is allowed as part of a software development kit, other library, * or development tool without written consent of Netspective. Any modified form of The Software is bound by these * same restrictions. * * 3. Redistributions of The Software in any form must include an unmodified copy of The License, normally in a plain * ASCII text file unless otherwise agreed to, in writing, by Netspective. * * 4. The names "Netspective", "Axiom", "Commons", "Junxion", and "Sparx" are trademarks of Netspective and may not be * used to endorse or appear in products derived from The Software without written consent of Netspective. * * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED REPRESENTATIONS AND * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, * ARE HEREBY DISCLAIMED. * * NETSPECTIVE AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE OR ANY THIRD PARTY AS A * RESULT OF USING OR DISTRIBUTING THE SOFTWARE. IN NO EVENT WILL NETSPECTIVE OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE, EVEN * IF IT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. */ package com.netspective.commons.text; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.io.PrintWriter; import java.io.Reader; import java.io.StringWriter; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import org.apache.commons.discovery.tools.DiscoverSingleton; import org.apache.oro.text.perl.Perl5Util; public class TextUtils { private static final TextUtils INSTANCE = (TextUtils) DiscoverSingleton.find(TextUtils.class, TextUtils.class.getName()); public static TextUtils getInstance() { return INSTANCE; } public static final Map JAVA_RESERVED_WORD_TRANSLATION_MAP = new HashMap(); public static final String[] BOOLEAN_CHOICES = new String[] { "yes", "no", "true", "false", "on", "off", "1", "0" }; static { JAVA_RESERVED_WORD_TRANSLATION_MAP.put("abstract", "_abstract"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("boolean", "_boolean"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("break", "_break"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("byte", "_byte"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("case", "_case"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("catch", "_catch"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("char", "_char"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("class", "_class"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("const", "_const"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("continue", "_continue"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("default", "_default"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("do", "_do"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("double", "_double"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("else", "_else"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("extends", "_extends"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("false", "_false"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("final", "_final"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("finally", "_finally"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("float", "_float"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("for", "_for"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("goto", "_goto"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("if", "_if"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("implements", "_implements"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("import", "_import"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("instanceof", "_instanceof"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("int", "_int"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("interface", "_interface"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("long", "_long"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("native", "_native"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("new", "_new"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("null", "_null"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("package", "_package"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("private", "_private"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("protected", "_protected"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("public", "_public"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("return", "_return"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("short", "_short"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("static", "_static"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("strictfp", "_strictfp"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("super", "_super"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("switch", "_switch"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("synchronized", "_synchronized"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("this", "_this"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("throw", "_throw"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("throws", "_throws"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("transient", "_transient"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("true", "_true"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("try", "_try"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("void", "_void"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("volatile", "_volatile"); JAVA_RESERVED_WORD_TRANSLATION_MAP.put("while", "_while"); } /** * Return the name of the given cls that is different from the relativeTo class. Basically, this chops off the * package name of the cls that is equivalent to that of the relativeTo class. */ public String getRelativeClassName(Class relativeTo, Class cls) { String className = cls.getName(); String relativeToPkg = relativeTo.getPackage().getName(); if (className.startsWith(relativeToPkg)) return className.substring(relativeToPkg.length() + 1); else return className; } public String getClassNameWithoutPackage(String pkgAndClassName, char sep) { int classNameDelimPos = pkgAndClassName.lastIndexOf(sep); return classNameDelimPos != -1 ? pkgAndClassName.substring(classNameDelimPos + 1) : pkgAndClassName; } /** * A version of getClassNameWithoutPackage with sensible defaults for most common usage: getting only the class * name (without the package name) for a Java class */ public String getClassNameWithoutPackage(String pkgAndClassName) { return getClassNameWithoutPackage(pkgAndClassName, '.'); } public String getPackageName(String pkgAndClassName, char sep) { int classNameDelimPos = pkgAndClassName.lastIndexOf(sep); return classNameDelimPos != -1 ? pkgAndClassName.substring(0, classNameDelimPos) : null; } /** * A version of getPackageName with sensible defaults for most common usage: getting the package name for a Java * class */ public String getPackageName(String pkgAndClassName) { return getPackageName(pkgAndClassName, '.'); } public String[] split(String source, String delimiter, boolean trim) { if (source == null) return null; if (null == delimiter) delimiter = " "; List list = new ArrayList(); StringTokenizer st = new StringTokenizer(source, delimiter); if (trim) { while (st.hasMoreTokens()) list.add(st.nextToken().trim()); } else { while (st.hasMoreTokens()) list.add(st.nextToken()); } return (String[]) list.toArray(new String[list.size()]); } /** * A version of split with sensible defaults for most common usage: splitting sentences into words */ public String[] split(String source) { return split(source, " ", false); } public String join(String[] source, String delimiter) { if (source == null) return null; if (null == delimiter) delimiter = ""; StringBuffer result = new StringBuffer(); for (int i = 0; i < source.length; i++) { result.append(source[i]); if (i < source.length - 1) result.append(delimiter); } return result.toString(); } /** * A version of join with sensible defaults for most common usage: concatenating multiple String objects together */ public String join(String[] source) { return join(source, ""); } /** * A version of join with an additional parameter (trim) which automatically trims each String in the source and * then does the join. */ public String join(String[] source, String delimiter, boolean trim) { if (trim) { for (int i = 0; i < source.length; i++) source[i] = source[i].trim(); } return join(source, delimiter); } /** * Ascertain whether the find string occurs in the source string list * * @param source The array to search * @param find The string to look for * * @return True if find is in source */ public boolean contains(String[] source, String find, boolean ignoreCase) { if (source != null) { if (ignoreCase) { for (int i = 0; i < source.length; i++) if (source[i].equalsIgnoreCase(find)) return true; } else { for (int i = 0; i < source.length; i++) if (source[i].equals(find)) return true; } } return false; } /** * Perform a simple string replacement of findStr to replStr in origStr and returns the result. All instances * of findStr are replaced to replStr (regardless of how many there are). Not optimized for performance. * * @param originalText The source text * @param findText The text to locate * @param replaceText The text to replace for each findStr */ public String replaceTextValues(final String originalText, final String findText, final String replaceText) { if (findText == null || replaceText == null) return originalText; final StringBuffer result = new StringBuffer(); //startIdx and idxOld delimit various chunks of aInput; these //chunks always end where aOldPattern begins int startIdx = 0; int idxOld = 0; while ((idxOld = originalText.indexOf(findText, startIdx)) >= 0) { //grab a part of aInput which does not include aOldPattern result.append(originalText.substring(startIdx, idxOld)); //add aNewPattern to take place of aOldPattern result.append(replaceText); //reset the startIdx to just after the current match, to see //if there are any further matches startIdx = idxOld + findText.length(); } //the final chunk will go to the end of aInput result.append(originalText.substring(startIdx)); return result.toString(); } /** * Perform a simple string replacement of findStr to replStr in all the members of origStr and returns the result. * All instances of findStr are replaced to replStr (regardless of how many there are). Not optimized for * performance. * * @param originalText An array containing all the source texts on which this replacement should be performed * @param findText The text to locate * @param replaceText The text to replace for each findStr */ public String[] replaceTextValues(final String[] originalText, final String findText, final String replaceText) { String[] returnValue = new String[originalText.length]; if (null == findText || null == replaceText) returnValue = originalText; else for (int i = 0; i < originalText.length; i++) returnValue[i] = replaceTextValues(originalText[i], findText, replaceText); return returnValue; } public String[] getBooleanChoices() { return BOOLEAN_CHOICES; } /** * returns the boolean equivalent of a string, which is considered true * if either "on", "true", or "yes" is found, ignoring case. */ public boolean toBoolean(String s) { return (s.equalsIgnoreCase("yes") || s.equalsIgnoreCase("true") || s.equalsIgnoreCase("on") || s.equalsIgnoreCase("1")); } /** * returns the boolean equivalent of a string, which is considered true but allows a default value if s is null */ public boolean toBoolean(String s, boolean valueIfNull) { if (s == null) return valueIfNull; else return toBoolean(s); } /** * Given some text, return it as a literal string (surrounded by single or double quotes). * * @param text The text to surround as SQL literal * @param surroundWith The string to place before and after the text * @param escapeText Any special text that should be replaced (like ' to '' or " to \") * @param replaceWith If escapeText is specified, this is the string to put in place of the escape * @param trim Remove leading and trailing spaces * @param stripNewLines True if newlines (carriage returns, etc) should be replaced by a single space * @param valueIfNullOrBlank The string to return if the string is null or has no text (blank string) * * @return The text surrounded by ' and with all internal ' characters escaped as '' */ public String createLiteral(String text, String surroundWith, String escapeText, String replaceWith, boolean trim, boolean stripNewLines, String valueIfNullOrBlank) { if (text == null || text.length() == 0) return valueIfNullOrBlank; if (stripNewLines) text = replaceTextValues(text, "\n", " "); if (trim) text = text.trim(); if (escapeText != null) text = replaceTextValues(text, escapeText, replaceWith); StringBuffer sb = new StringBuffer(surroundWith); sb.append(text); sb.append(surroundWith); return sb.toString(); } /** * Given a text string that defines a SQL table name or column name or other SQL identifier, * return a string that would be suitable for that string to be used as a caption or plain text. */ public String sqlIdentifierToText(String original, boolean uppercaseEachWord) { if (original == null || original.length() == 0) return original; StringBuffer text = new StringBuffer(); text.append(Character.toUpperCase(original.charAt(0))); boolean wordBreak = false; for (int i = 1; i < original.length(); i++) { char ch = original.charAt(i); if (ch == '_') { text.append(' '); wordBreak = true; } else if (wordBreak) { text.append(uppercaseEachWord ? Character.toUpperCase(ch) : Character.toLowerCase(ch)); wordBreak = false; } else text.append(Character.toLowerCase(ch)); } return text.toString(); } /** * Given a method name, return a string that would be suitable for that string to be used * as a xml node name. Basically, what this does is allows something like setAbcDef() to * match both "abcDef" and "abc-def" as node names in XML. It turns a java identifier into * a reasonable xml node name. */ public String javaIdentifierToXmlNodeName(final String javaIdentifier) { if (javaIdentifier == null || javaIdentifier.length() == 0) return javaIdentifier; StringBuffer nodeName = new StringBuffer(); nodeName.append(javaIdentifier.charAt(0)); for (int i = 1; i < javaIdentifier.length(); i++) { //TODO: Might be a good idea to replace _ with - and to lower the case of any uppercase letters char ch = javaIdentifier.charAt(i); if (Character.isLowerCase(ch)) nodeName.append(ch); else { nodeName.append('-'); nodeName.append(ch); } } return nodeName.toString(); } /** * Given a text string, return a string that would be suitable for that string to be used * as a Java identifier (as a variable or method name). Depending upon whether ucaseInitial * is set, the string starts out with a lowercase or uppercase letter. Then, the rule is * to convert all periods into underscores and title case any words separated by * underscores. This has the effect of removing all underscores and creating mixed case * words. For example, Person_Address becomes personAddress or PersonAddress depending upon * whether ucaseInitial is set to true or false. Person.Address would become Person_Address. */ public String xmlTextToJavaIdentifier(String xml, boolean ucaseInitial) { if (xml == null || xml.length() == 0) return xml; String translated = (String) JAVA_RESERVED_WORD_TRANSLATION_MAP.get(xml.toString().toLowerCase()); if (translated != null) xml = translated; StringBuffer identifier = new StringBuffer(); char ch = xml.charAt(0); if (Character.isJavaIdentifierStart(ch)) identifier.append(ucaseInitial ? Character.toUpperCase(ch) : Character.toLowerCase(ch)); else { identifier.append('_'); if (Character.isJavaIdentifierPart(ch)) identifier.append(ucaseInitial ? Character.toUpperCase(ch) : Character.toLowerCase(ch)); } boolean uCase = false; for (int i = 1; i < xml.length(); i++) { ch = xml.charAt(i); if (ch == '.') { identifier.append('_'); } else if (ch != '_' && Character.isJavaIdentifierPart(ch)) { identifier.append(Character.isUpperCase(ch) ? ch : (uCase ? Character.toUpperCase(ch) : Character.toLowerCase(ch))); uCase = false; } else uCase = true; } return identifier.toString(); } /** * Given a text string, return a string that would be suitable for that string to be used * as a Java package name. The rule is to leave all periods and treat words as XML identifiers. */ public String xmlTextToJavaPackageName(String xml) { if (xml == null || xml.length() == 0) return xml; StringBuffer result = new StringBuffer(); StringTokenizer st = new StringTokenizer(xml, "."); while (st.hasMoreTokens()) { result.append(xmlTextToJavaIdentifier(st.nextToken(), false).toLowerCase()); if (st.hasMoreTokens()) result.append("."); } return result.toString(); } /** * Given a text string, return a string that would be suitable for that string to be used * as a Java constant (public static final XXX). The rule is to basically take every letter * or digit and return it in uppercase and every non-letter or non-digit as an underscore. */ public String xmlTextToJavaConstant(String xml) { if (xml == null || xml.length() == 0) return xml; StringBuffer constant = new StringBuffer(); for (int i = 0; i < xml.length(); i++) { char ch = xml.charAt(i); constant.append(Character.isJavaIdentifierPart(ch) ? Character.toUpperCase(ch) : '_'); } return constant.toString(); } /** * Given a text string, return a string that would be suitable for that string to be used * as a Java constant (public static final XXX). The rule is to basically take every letter * or digit and return it in uppercase and every non-letter or non-digit as an underscore. * This trims all non-letter/digit characters from the beginning of the string. */ public String xmlTextToJavaConstantTrimmed(String xml) { if (xml == null || xml.length() == 0) return xml; boolean stringStarted = false; StringBuffer constant = new StringBuffer(); for (int i = 0; i < xml.length(); i++) { char ch = xml.charAt(i); if (Character.isJavaIdentifierPart(ch)) { stringStarted = true; constant.append(Character.toUpperCase(ch)); } else if (stringStarted) constant.append('_'); } return constant.toString(); } /** * Given a text string, return a string that would be suitable for an XML element name. For example, * when given Person_Address it would return person-address. The rule is to basically take every letter * or digit and return it in lowercase and every non-letter or non-digit as a dash. */ public String xmlTextToNodeName(String xml) { if (xml == null || xml.length() == 0) return xml; StringBuffer constant = new StringBuffer(); for (int i = 0; i < xml.length(); i++) { char ch = xml.charAt(i); constant.append(Character.isLetterOrDigit(ch) ? Character.toLowerCase(ch) : '-'); } return constant.toString(); } /** * Return the given text unindented by whatever the first line is indented by * * @param text The original text * * @return Unindented text or original text if not indented */ public String getUnindentedText(String text) { /* * if the string is indented, find out how far the first line is indented */ StringBuffer replStr = new StringBuffer(); for (int i = 0; i < text.length(); i++) { char ch = text.charAt(i); if (Character.isWhitespace(ch)) replStr.append(ch); else break; } /* * If the first line is indented, unindent all the lines the distance of just the first line */ Perl5Util perlUtil = new Perl5Util(); if (replStr.length() > 0) return perlUtil.substitute("s/^" + replStr + "//gm", text).trim(); else return text; } public String getStackTrace(Throwable t) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); t.printStackTrace(pw); return sw.toString(); } /** * Return the given block of text indented by the given string. * * @param text The original text * * @return Unindented text or original text if not indented */ public String getIndentedText(String text, String indent, boolean appendNewLine) { text = getUnindentedText(text); /* * If the first line is indented, unindent all the lines the distance of just the first line */ Perl5Util perlUtil = new Perl5Util(); text = perlUtil.substitute("s/^/" + indent + "/gm", text); return appendNewLine ? text + "\n" : text; } /* make the table name title cased (cap each letter after _) */ public String fixupTableNameCase(String tableNameOrig) { if (null == tableNameOrig) return null; StringBuffer tableNameBuf = new StringBuffer(tableNameOrig.toLowerCase()); boolean capNext = false; for (int i = 0; i < tableNameBuf.length(); i++) { if (tableNameBuf.charAt(i) == '_') capNext = true; else { if (i == 0 || capNext) { tableNameBuf.setCharAt(i, Character.toUpperCase(tableNameBuf.charAt(i))); capNext = false; } } } return tableNameBuf.toString(); } /** * Check if the given string is null, empty or made up only of whitespace. * * @param value a tested string * * @return true if the string is empty */ public boolean isEmpty(String value) { if (value == null) return true; if (value.length() == 0) return true; if (value.trim().length() == 0) return true; return false; } /** * Retrieve the contents of the given URL into a String. * * @param strLocation The URL * * @return The text of the contents of the URL */ public String getUrlContents(String strLocation) throws IOException { StringBuffer sb = new StringBuffer(); URL url = new URL(strLocation); URLConnection urlConn = url.openConnection(); InputStream urlIn = urlConn.getInputStream(); int iRead = urlIn.read(); while (iRead != -1) { sb.append((char) iRead); iRead = urlIn.read(); } return sb.toString(); } /** * Retrieve the contents of the given File into a String. * * @param location The URL * * @return The text of the contents of the File */ public String getFileContents(String location) throws IOException { StringBuffer sb = new StringBuffer(); InputStream is = new BufferedInputStream(new FileInputStream(location)); int iRead = is.read(); while (iRead != -1) { sb.append((char) iRead); iRead = is.read(); } return sb.toString(); } public String pad(String text, int length, String fillWith) { if (text != null && text.length() > length) return text; if (text == null) text = ""; StringBuffer sb = new StringBuffer(text); while (sb.length() < length) sb.append(fillWith); return sb.toString(); } /** * Retrieve lines of text from an input stream * * @param location The fully qualified name of the file to read * @param startLineNumber The starting line number * @param endLineNumber The ending line number * * @return The text contained in line numbers startingLineNumber to endingLineNumber */ public String getTextFileLines(String location, int startLineNumber, int endLineNumber) throws IOException { return getTextStreamLines(new FileInputStream(location), startLineNumber, endLineNumber); } /** * Retrieve lines of text from an input stream * * @param is The input stream to read * @param startLineNumber The starting line number * @param endLineNumber The ending line number * * @return The text contained in line numbers startingLineNumber to endingLineNumber */ public String getTextStreamLines(InputStream is, int startLineNumber, int endLineNumber) throws IOException { if (is == null) return null; if (startLineNumber <= 0 && endLineNumber <= 0) return null; Reader isReader = null; LineNumberReader reader = null; StringBuffer result = new StringBuffer(); try { isReader = new InputStreamReader(is); reader = new LineNumberReader(isReader); String line = null; if (startLineNumber > 0 && endLineNumber <= 0) { while ((line = reader.readLine()) != null) { if (reader.getLineNumber() == startLineNumber) return line; } } else { while ((line = reader.readLine()) != null) { int lineNumber = reader.getLineNumber(); if (lineNumber < startLineNumber) continue; if (lineNumber > endLineNumber) break; result.append(line); result.append("\n"); } } } finally { if (reader != null) reader.close(); if (isReader != null) is.close(); is.close(); } return result.toString(); } public final String escapeHTML(String s) { if (s == null) return null; StringBuffer sb = new StringBuffer(); int n = s.length(); for (int i = 0; i < n; i++) { char c = s.charAt(i); switch (c) { case '<': sb.append("<"); break; case '>': sb.append(">"); break; case '&': sb.append("&"); break; case '"': sb.append("""); break; case '': sb.append("à"); break; case '': sb.append("À"); break; case '': sb.append("â"); break; case '': sb.append("Â"); break; case '': sb.append("ä"); break; case '': sb.append("Ä"); break; case '': sb.append("å"); break; case '': sb.append("Å"); break; case '': sb.append("æ"); break; case '': sb.append("Æ"); break; case '': sb.append("ç"); break; case '': sb.append("Ç"); break; case '': sb.append("é"); break; case '': sb.append("É"); break; case '': sb.append("è"); break; case '': sb.append("È"); break; case '': sb.append("ê"); break; case '': sb.append("Ê"); break; case '': sb.append("ë"); break; case '': sb.append("Ë"); break; case '': sb.append("ï"); break; case '': sb.append("Ï"); break; case '': sb.append("ô"); break; case '': sb.append("Ô"); break; case '': sb.append("ö"); break; case '': sb.append("Ö"); break; case '': sb.append("ø"); break; case '': sb.append("Ø"); break; case '': sb.append("ß"); break; case '': sb.append("ù"); break; case '': sb.append("Ù"); break; case '': sb.append("û"); break; case '': sb.append("Û"); break; case '': sb.append("ü"); break; case '': sb.append("Ü"); break; case '': sb.append("®"); break; case '': sb.append("©"); break; case '': sb.append("€"); break; default: sb.append(c); break; } } return sb.toString(); } }