package kr.kangwoo.util;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class StringUtils {

	public static final String EMPTY = ""; //$NON-NLS-1$
	public static final String NULL = "null"; //$NON-NLS-1$
	public static final char[] WORD_SEPARATORS = {'_', '-', '@', '$', '#', ' '};
	public static final int INDEX_NOT_FOUND = -1;
	
	public static final String LINE_SEPARATOR = System.getProperty("line.separator");

	
	private StringUtils() {
	}
	
	/**
	 * <p>¹®ÀÚ(char)°¡ ´Ü¾î ±¸ºÐÀÚ('_', '-', '@', '$', '#', ' ')ÀÎÁö ÆÇ´ÜÇÑ´Ù.</p>
	 * 
	 * @param c ¹®ÀÚ(char)
	 * @return ´Ü¾î ±¸ºÐÀÚÀÌ¸é true, ¾Æ´Ï¸é false¸¦ ¹ÝÈ¯ÇÑ´Ù.
	 */
	public static boolean isWordSeparator(char c) {
		for (int i = 0; i < WORD_SEPARATORS.length; i++) {
			if (WORD_SEPARATORS[i] == c) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * <p>¹®ÀÚ(char)°¡ ´Ü¾î ±¸ºÐÀÚ(wordSeparators)ÀÎÁö ÆÇ´ÜÇÑ´Ù.</p>
	 * <p>´Ü¾î ±¸ºÐÀÚ°¡ <code>null</code>ÀÌ¸é false¸¦ ¹ÝÈ¯ÇÑ´Ù.</p>
	 * 
	 * @param c ¹®ÀÚ(char)
	 * @param wordSeparators ´Ü¾î ±¸ºÐÀÚ
	 * @return ´Ü¾î ±¸ºÐÀÚÀÌ¸é true, ¾Æ´Ï¸é false¸¦ ¹ÝÈ¯ÇÑ´Ù.
	 */
	public static boolean isWordSeparator(char c, char[] wordSeparators) {
		if (wordSeparators == null) {
			return false;
		}
		for (int i = 0; i < wordSeparators.length; i++) {
			if (wordSeparators[i] == c) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * <p>¹®ÀÚ¿­(String)À» Ä«¸áÇ¥±â¹ýÀ¸·Î Ç¥ÇöÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.camelString("ITEM_CODE", true)  = "ItemCode"
	 * StringUtils.camelString("ITEM_CODE", false) = "itemCode"
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @param firstCharacterUppercase Ã¹¹®ÀÚ¿­À» ´ë¹®ÀÚ·Î ÇÒÁö ¿©ºÎ
	 * @return Ä«¸áÇ¥±â¹ýÀ¸·Î Ç¥ÇöÈ¯ ¹®ÀÚ¿­
	 */
	public static String camelString(String str, boolean firstCharacterUppercase) {
		if (str == null) {
			return null;
		}
		
		StringBuilder sb = new StringBuilder(str.length());
		
		boolean nextUpperCase = false;
		for (int i = 0; i < str.length(); i++) {
			char c = str.charAt(i);
			
			if (isWordSeparator(c)) {
				if (sb.length() > 0) {
					nextUpperCase = true;
				}
			} else {
				if (nextUpperCase) {
					sb.append(Character.toUpperCase(c));
					nextUpperCase = false;
				} else {
					sb.append(Character.toLowerCase(c));
				}
			}
		}
		
		if (firstCharacterUppercase) {
			sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
		}
		return sb.toString();
	}
	
	/**
	 * <p>ÀÔ·Â ¹ÞÀº ¹®ÀÚ¸¦ ¹Ýº¹¼ýÀÚ¸¸Å­ ºÙ¿©¼­ ¸¸µç´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.repeat(null, *)   = null
	 * StringUtils.repeat("", -1)    = ""
	 * StringUtils.repeat("", 2)     = ""
	 * StringUtils.repeat("han", -1) = ""
	 * StringUtils.repeat("han", 0)  = ""
	 * StringUtils.repeat("han", 2)  = "hanhan"
	 * </pre>
	 * 
	 * @param str
	 * @param repeat ¹Ýº¹¼ýÀÚ
	 * @return
	 */
	public static String repeat(String str, int repeat) {
		if (str == null) {
			return null;
		}
		if (repeat < 1) {
			return EMPTY;
		}
		int inputLen = str.length();
		if (inputLen == 0 || repeat == 1) {
			return str;
		}
		int outputLen = inputLen * repeat;
		if (inputLen == 1) {
			char ch = str.charAt(0);
			char[] output = new char[outputLen];
			for (int i = 0; i < outputLen; i++) {
				output[i] = ch;
			}
			return new String(output);
		} else {
			StringBuilder output = new StringBuilder(outputLen);
			for (int i = 0; i < repeat; i++) {
				output.append(str);
			}
			return output.toString();
		}
	}
	
	// ----------------------------------------------------------------------
	// °ø¹é/¿©¹é¹®ÀÚ  °Ë»ç, Á¦°Å, Ä¡È¯
	// ----------------------------------------------------------------------
	
	/**
	 * <p>¹®ÀÚ¿­(String)ÀÇ ÁÂ¿ì ¿©¹é¹®ÀÚ(white space)¸¦ Á¦°ÅÇÑÈÄ, °ø¹é("")ÀÌ°Å³ª <code>null</code>ÀÎ °Ë»çÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.isBlank(null)    = true
	 * StringUtils.isBlank("")      = true
	 * StringUtils.isBlank("   ")   = true
	 * StringUtils.isBlank("han")   = false
	 * StringUtils.isBlank(" han ") = false
	 * </pre> 
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @return
	 */
	public static boolean isBlank(String str) {
		if (str == null) {
			return true;
		}
		int strLen = str.length();
		if (strLen > 0) {
			for (int i = 0; i < strLen; i++) {
				if (Character.isWhitespace(str.charAt(i)) == false) {
					return false;
				}
			}
		}
		return true;
	}
	
	/**
	 * <p>¹®ÀÚ¿­(String)ÀÇ ÁÂ¿ì ¿©¹é¹®ÀÚ(white space)¸¦ Á¦°ÅÇÑÈÄ, °ø¹é("")ÀÌ ¾Æ´Ï°Å³ª <code>null</code>ÀÌ ¾Æ´ÑÁö °Ë»çÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.isNotBlank(null)    = false
	 * StringUtils.isNotBlank("")      = false
	 * StringUtils.isNotBlank("   ")   = false
	 * StringUtils.isNotBlank("han")   = true
	 * StringUtils.isNotBlank(" han ") = true
	 * </pre> 
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @return
	 */
	public static boolean isNotBlank(String str) {
		return !isBlank(str);
	}
	
	/**
	 * <p>¹®ÀÚ¿­(String)ÀÌ °ø¹é("")ÀÌ°Å³ª <code>null</code>ÀÎ °Ë»çÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.isEmpty(null)    = true
	 * StringUtils.isEmpty("")      = true
	 * StringUtils.isEmpty("   ")   = false
	 * StringUtils.isEmpty("han")   = false
	 * StringUtils.isEmpty(" han ") = false
	 * </pre>
	 * 
	 * 
	 * @param str °Ë»çÇÒ ¹®ÀÚ¿­
	 * @return
	 */
	public static boolean isEmpty(String str) {
		return str == null || str.length() == 0;
	}
	
	/**
	 * <p>¹®ÀÚ¿­(String)ÀÌ °ø¹é("")ÀÌ ¾Æ´Ï°Å³ª <code>null</code>ÀÌ ¾Æ´ÑÁö °Ë»çÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.isNotEmpty(null)    = false
	 * StringUtils.isNotEmpty("")      = false
	 * StringUtils.isNotEmpty("   ")   = true
	 * StringUtils.isNotEmpty("han")   = true
	 * StringUtils.isNotEmpty(" han ") = true
	 * </pre>
	 * 
	 * @param str °Ë»çÇÒ ¹®ÀÚ¿­
	 * @return
	 */
	public static boolean isNotEmpty(String str) {
		return !isEmpty(str);
	}
	
	/**
	 * <p>¹®ÀÚ¿­(String)ÀÇ ÁÂ¿ì ¿©¹é¹®ÀÚ(white space)¸¦ Á¦°ÅÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.trim(null)    = null
	 * StringUtils.trim("")      = ""
	 * StringUtils.trim("   ")   = ""
	 * StringUtils.trim("han")   = "han"
	 * StringUtils.trim(" han ") = "han"
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @return
	 */
	public static String trim(String str) {
		return str == null ? null : str.trim();
	}
	
	/**
	 * <p>¹®ÀÚ¿­(String)ÀÇ ÁÂ¿ì ¿©¹é¹®ÀÚ(white space)¸¦ Á¦°ÅÇÑ ÈÄ °ø¹é("")ÀÌ°Å³ª <code>null</code>ÀÌ¸é <code>null</code>À» ¹ÝÈ¯ÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.trimToNull(null)    = null
	 * StringUtils.trimToNull("")      = null
	 * StringUtils.trimToNull("   ")   = null
	 * StringUtils.trimToNull("han")   = "han"
	 * StringUtils.trimToNull(" han ") = "han"
	 * </pre>
	 *
	 * @param str ¹®ÀÚ¿­
	 * @return
	 */
	public static String trimToNull(String str) {
		return isBlank(str) ? null : trim(str);
	}
	
	/**
	 * <p>¹®ÀÚ¿­(String)ÀÇ ÁÂ¿ì ¿©¹é¹®ÀÚ(white space)¸¦ Á¦°ÅÇÑ ÈÄ °ø¹é("")ÀÌ°Å³ª <code>null</code>ÀÌ¸é °ø¹é("")À» ¹ÝÈ¯ÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.trimToEmpty(null)    = ""
	 * StringUtils.trimToEmpty("")      = ""
	 * StringUtils.trimToEmpty("   ")   = ""
	 * StringUtils.trimToEmpty("han")   = "han"
	 * StringUtils.trimToEmpty(" han ") = "han"
	 * </pre>
	 *
	 * @param str ¹®ÀÚ¿­
	 * @return
	 */
	public static String trimToEmpty(String str) {
		return isBlank(str) ? EMPTY : trim(str);
	}
	
	/**
	 * <p>¹®ÀÚ¿­(String)ÀÌ <code>null</code>ÀÌ¸é ±âº»¹®ÀÚ¿­À» ¹ÝÈ¯ÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.defaultIfNull(null, "")    = ""
	 * StringUtils.defaultIfNull("", "")      = ""
	 * StringUtils.defaultIfNull("   ", "")   = "   "
	 * StringUtils.defaultIfNull("han", "")   = "han"
	 * StringUtils.defaultIfNull(" han ", "") = " han "
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @param defaultStr ±âº»¹®ÀÚ¿­
	 * @return
	 */
	public static String defaultIfNull(String str, String defaultStr) {
		return str == null ? defaultStr : str;
	}
	
	/**
	 * <p>¹®ÀÚ¿­(String)ÀÌ <code>null</code>ÀÌ¸é °ø¹é¹®ÀÚ¿­À» ¹ÝÈ¯ÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.defaultIfNull(null)    = ""
	 * StringUtils.defaultIfNull("")      = ""
	 * StringUtils.defaultIfNull("   ")   = "   "
	 * StringUtils.defaultIfNull("han")   = "han"
	 * StringUtils.defaultIfNull(" han ") = " han "
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @return
	 */
	public static String defaultIfNull(String str) {
		return defaultIfNull(str, EMPTY);
	}
	
	/**
	 * <p>¹®ÀÚ¿­(String)ÀÇ ÁÂ¿ì ¿©¹é¹®ÀÚ(white space)¸¦ Á¦°ÅÇÑÈÄ, °ø¹é("")ÀÌ°Å³ª <code>null</code>ÀÌ¸é, ±âº»¹®ÀÚ¿­À» ¹ÝÈ¯ÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.defaultIfBlank(null, "")    = ""
	 * StringUtils.defaultIfBlank("", "")      = ""
	 * StringUtils.defaultIfBlank("   ", "")   = ""
	 * StringUtils.defaultIfBlank("han", "")   = "han"
	 * StringUtils.defaultIfBlank(" han ", "") = " han "
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @param defaultStr ±âº»¹®ÀÚ¿­
	 * @return
	 */
	public static String defaultIfBlank(String str, String defaultStr) {
		return isBlank(str) ? defaultStr : str;
	}
	
	/**
	 * <p>¹®ÀÚ¿­(String)ÀÇ ÁÂ¿ì ¿©¹é¹®ÀÚ(white space)¸¦ Á¦°ÅÇÑÈÄ, °ø¹é("")ÀÌ°Å³ª <code>null</code>ÀÌ¸é, °ø¹é¹®ÀÚ¿­À» ¹ÝÈ¯ÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.defaultIfBlank(null)    = ""
	 * StringUtils.defaultIfBlank("")      = ""
	 * StringUtils.defaultIfBlank("   ")   = ""
	 * StringUtils.defaultIfBlank("han")   = "han"
	 * StringUtils.defaultIfBlank(" han ") = " han "
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @return
	 */
	public static String defaultIfBlank(String str) {
		return defaultIfBlank(str, EMPTY);
	}
	
	
	// ----------------------------------------------------------------------
	// ¹®ÀÚ¿­ ºñ±³
	// ----------------------------------------------------------------------
	/**
	 * <p>µÎ ¹®ÀÚ¿­(String)ÀÌ ÀÏÄ¡ÇÏ¸é <code>true</code>À» ¹ÝÈ¯ÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.equals(null, null)   = true
	 * StringUtils.equals(null, "")     = false
	 * StringUtils.equals("", null)     = false
	 * StringUtils.equals(null, "han")  = false
	 * StringUtils.equals("han", null)  = false
	 * StringUtils.equals("han", "han") = true
	 * StringUtils.equals("han", "HAN") = false
	 * </pre>
	 * 
	 * @see java.lang.String#equals(Object)
	 * @param str1 Ã¹¹øÂ° ¹®ÀÚ¿­
	 * @param str2 µÎ¹øÂ° ¹®ÀÚ¿­
	 * @return ¹®ÀÚ¿­(String)ÀÌ ÀÏÄ¡ÇÏ¸é <code>true</code>
	 */
	public static boolean equals(String str1, String str2) {
		return str1 == null ? str2 == null : str1.equals(str2);
	}
	
	/**
	 * <p>´ë¼Ò¹®ÀÚ¸¦ ¹«½ÃÇÑ, µÎ ¹®ÀÚ¿­(String)ÀÌ ÀÏÄ¡ÇÏ¸é <code>true</code>À» ¹ÝÈ¯ÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.equalsIgnoreCase(null, null)   = true
	 * StringUtils.equalsIgnoreCase(null, "")     = false
	 * StringUtils.equalsIgnoreCase("", null)     = false
	 * StringUtils.equalsIgnoreCase(null, "han")  = false
	 * StringUtils.equalsIgnoreCase("han", null)  = false
	 * StringUtils.equalsIgnoreCase("han", "han") = true
	 * StringUtils.equalsIgnoreCase("han", "HAN") = true
	 * </pre>
	 * 
	 * @see java.lang.String#equalsIgnoreCase(String)
	 * @param str1 Ã¹¹øÂ° ¹®ÀÚ¿­
	 * @param str2 µÎ¹øÂ° ¹®ÀÚ¿­
	 * @return ´ë¼Ò¹®ÀÚ¸¦ ¹«½ÃÇÑ ¹®ÀÚ¿­(String)ÀÌ ÀÏÄ¡ÇÏ¸é <code>true</code>
	 */
	public static boolean equalsIgnoreCase(String str1, String str2) {
		return str1 == null ? str2 == null : str1.equalsIgnoreCase(str2);
	}
	
	/**
	 * <p>¹®ÀÚ¿­ÀÌ Á¢µÎ»ç·Î ½ÃÀÛÇÏ´ÂÁö¸¦ ÆÇ´ÜÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.startsWith(null, *)    = false
	 * StringUtils.startsWith(*, null)    = false
	 * StringUtils.startsWith("han", "h") = true
	 * StringUtils.startsWith("han", "a") = false
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @param prefix Á¢µÎ»ç
	 * @return
	 */
	public static boolean startsWith(String str, String prefix) {
		if (str == null || prefix == null) {
			return false;
		}
		return str.startsWith(prefix);
	}
	
	/**
	 * <p>¹®ÀÚ¿­ offset À§Ä¡ºÎÅÍ Á¢µÎ»ç·Î ½ÃÀÛÇÏ´ÂÁö¸¦ ÆÇ´ÜÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.startsWith(null, *, 0)    = false
	 * StringUtils.startsWith(*, null, 0)    = false
	 * StringUtils.startsWith("han", "h", 0) = true
	 * StringUtils.startsWith("han", "a", 0) = false
	 * StringUtils.startsWith("han", "a", 1) = true
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @param prefix Á¢µÎ»ç
	 * @param offset ºñ±³ ½ÃÀÛ À§Ä¡
	 * @return
	 */
	public static boolean startsWith(String str, String prefix, int offset) {
		if (str == null || prefix == null) {
			return false;
		}
		return str.startsWith(prefix, offset);
	}
	
	/**
	 * <p>¹®ÀÚ¿­ÀÌ Á¢¹Ì»ç·Î ³¡³ª´ÂÁö¸¦ ÆÇ´ÜÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.endsWith(null, *)    = false
	 * StringUtils.endsWith(*, null)    = false
	 * StringUtils.endsWith("han", "h") = false
	 * StringUtils.endsWith("han", "n") = true
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @param prefix Á¢µÎ»ç
	 * @return
	 */
	public static boolean endsWith(String str, String suffix) {
		if (str == null || suffix == null) {
			return false;
		}
		return str.endsWith(suffix);
	}

	/**
	 * <p>¹®ÀÚ¿­(String)¿¡ °Ë»ö¹®ÀÚ¿­(String)ÀÌ Æ÷ÇÔµÇ¾î ÀÖ´ÂÁö °Ë»çÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.contains(null, *)    = false
	 * StringUtils.contains(*, null)    = false
	 * StringUtils.contains("han", "")  = true
	 * StringUtils.contains("han", "h") = true
	 * StringUtils.contains("han", "H") = false
	 * </pre>
	 * 
	 * @see java.lang.String#indexOf(String)
	 * @param str ¹®ÀÚ¿­
	 * @param searchStr °Ë»ö¹®ÀÚ¿­
	 * @return ¹®ÀÚ¿­(String)¿¡ °Ë»ö ¹®ÀÚ¿­ÀÌ Æ÷ÇÔµÇ¾î ÀÖÀ»¶§ <code>true</code>,
	 *  ¹®ÀÚ¿­(String)¿¡ °Ë»ö ¹®ÀÚ¿­ÀÌ Æ÷ÇÔµÇ¾î ÀÖÁö ¾ÊÀ»¶§³ª, ¹®ÀÚ¿­ ¶Ç´Â °Ë»ö¹®ÀÚ¿­ÀÌ <code>null</code>ÀÏ¶§ <code>false</code>
	 */
	public static boolean contains(String str, String searchStr) {
		if (str == null || searchStr == null) {
			return false;
		}
		return str.indexOf(searchStr) > INDEX_NOT_FOUND;
	}
	
	
	
	// ----------------------------------------------------------------------
	// ´ë/¼Ò¹®ÀÚ º¯È¯
	// ----------------------------------------------------------------------
	/**
	 * <p>¹®ÀÚ¿­(String)À» ´ë¹®ÀÚ·Î º¯È¯ÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.toUpperCase(null)  = null
	 * StringUtils.toUpperCase("han") = "HAN"
	 * StringUtils.toUpperCase("hAn") = "HAN"
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @return ´ë¹®ÀÚ·Î º¯È¯ÇÑ ¹®ÀÚ¿­
	 */
	public static String toUpperCase(String str) {
		if (str == null) {
			return null;
		}
		return str.toUpperCase();
	}
	
	/**
	 * <p>½ÃÀÛ ÀÎµ¦½ººÎÅÍ Á¾·á ÀÎµ¦½º±îÁö ´ë¹®ÀÚ·Î º¯È¯ÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.toUpperCase(null, *, *)  = null
	 * StringUtils.toUpperCase("han", 0, 1) = "Han"
	 * StringUtils.toUpperCase("han", 0, 2) = "HAn"
	 * StringUtils.toUpperCase("han", 0, 3) = "HAN"
	 * </pre>
	 * 
	 * @param str
	 * @param beginIndex
	 * @param endIndex
	 * @return
	 */
	public static String toUpperCase(String str, int beginIndex, int endIndex) {
		if (str == null) {
			return null;
		}
		StringBuilder sb = new StringBuilder(str.length());
		if (beginIndex < 0) {
			beginIndex = 0;
		}
		if (endIndex > str.length()) {
			endIndex = str.length();
		}
		if (beginIndex > 0) {
			sb.append(str.substring(0, beginIndex));
		}
		sb.append(str.substring(beginIndex, endIndex).toUpperCase());
		if (endIndex < str.length()) {
			sb.append(str.substring(endIndex));	
		}
		return sb.toString();
	}
	
	/**
	 * <p>¹®ÀÚ¿­(String)À» ¼Ò¹®ÀÚ·Î º¯È¯ÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.toLowerCase(null)  = null
	 * StringUtils.toLowerCase("han") = "han"
	 * StringUtils.toLowerCase("hAn") = "han"
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @return ¼Ò¹®ÀÚ·Î º¯È¯ÇÑ ¹®ÀÚ¿­
	 */
	public static String toLowerCase(String str) {
		if (str == null) {
			return null;
		}
		return str.toLowerCase();
	}
	
	/**
	 * <p>½ÃÀÛ ÀÎµ¦½ººÎÅÍ Á¾·á ÀÎµ¦½º±îÁö ¼Ò¹®ÀÚ·Î º¯È¯ÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.toLowerCase(null, *, *)  = null
	 * StringUtils.toLowerCase("HAN", 0, 1) = "hAN"
	 * StringUtils.toLowerCase("HAN", 0, 2) = "haN"
	 * StringUtils.toLowerCase("HAN", 0, 3) = "han"
	 * </pre>
	 * 
	 * @param str
	 * @param beginIndex
	 * @param endIndex
	 * @return
	 */
	public static String toLowerCase(String str, int beginIndex, int endIndex) {
		if (str == null) {
			return null;
		}
		StringBuilder sb = new StringBuilder(str.length());
		if (beginIndex < 0) {
			beginIndex = 0;
		}
		if (endIndex > str.length()) {
			endIndex = str.length();
		}
		if (beginIndex > 0) {
			sb.append(str.substring(0, beginIndex));
		}
		sb.append(str.substring(beginIndex, endIndex).toLowerCase());
		if (endIndex < str.length()) {
			sb.append(str.substring(endIndex));	
		}
		return sb.toString();
	}
	
	/**
	 * <p>´ë¹®ÀÚ´Â ¼Ò¹®ÀÚ·Î º¯È¯ÇÏ°í ¼Ò¹®ÀÚ´Â ´ë¹®ÀÚ·Î º¯È¯ÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.swapCase(null)  = null
	 * StringUtils.swapCase("Han") = "hAN"
	 * StringUtils.swapCase("hAn") = "HaN"
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @return
	 */
	public static String swapCase(String str) {
		if (str == null) {
			return null;
		}
		char[] charArray = str.toCharArray();
		for (int i = 0; i < charArray.length; i++) {
			if (Character.isLowerCase(charArray[i])) {
				charArray[i] = Character.toUpperCase(charArray[i]);
			} else {
				charArray[i] = Character.toLowerCase(charArray[i]);
			}
		}
		
		return new String(charArray);
	}

	/**
	 * ¹®ÀÚ¿­(String)ÀÇ Ã¹¹øÂ° ¹®ÀÚ¸¦ ´ë¹®ÀÚ·Î º¯È¯ÇÑ´Ù.
	 * 
	 * <pre>
	 * StringUtils.capitalize(null)  = null
	 * StringUtils.capitalize("Han") = "Han"
	 * StringUtils.capitalize("han") = "Han"
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @return Ã¹¹øÂ° ¹®ÀÚ¸¦ ´ë¹®ÀÚ·Î º¯È¯ÇÑ ¹®ÀÚ¿­
	 */
	public static String capitalize(String str) {
		if (str == null) {
			return null;
		}
		char[] charArray = str.toCharArray();
		if (charArray.length > 0) {
			charArray[0] = Character.toUpperCase(charArray[0]);
		}
		return new String(charArray);
	}
	
	/**
	 * ¹®ÀÚ¿­(String)ÀÇ Ã¹¹øÂ° ¹®ÀÚ¸¦ ¼Ò¹®ÀÚ·Î º¯È¯ÇÑ´Ù.
	 * 
	 * <pre>
	 * StringUtils.uncapitalize(null)  = null
	 * StringUtils.uncapitalize("han") = "han"
	 * StringUtils.uncapitalize("HAN") = "hAN"
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @return Ã¹¹øÂ° ¹®ÀÚ¸¦ ´ë¹®ÀÚ·Î º¯È¯ÇÑ ¹®ÀÚ¿­
	 */
	public static String uncapitalize(String str) {
		if (str == null) {
			return null;
		}
		char[] charArray = str.toCharArray();
		if (charArray.length > 0) {
			charArray[0] = Character.toLowerCase(charArray[0]);
		}
		return new String(charArray);
	}
	
	// ----------------------------------------------------------------------
	// ¹®ÀÚ¿­ ¹è¿­ °áÇÕ/ºÐ¸®
	// ----------------------------------------------------------------------
	/**
	 * <p>¹®ÀÚ¿­ ¹è¿­À» ÇÏ³ªÀÇ ¹®ÀÚ¿­·Î °áÇÕ½ÃÅ²´Ù.</p>
	 * <p>¹è¿­ÀÇ ¹®ÀÚ¿­ Áß¿¡ <code>null</code>°ú °ø¹é("")Àº ¹«½ÃÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.compose(null, *)               = ""
	 * StringUtils.compose(["h", "a", "n"], ".")  = "h.a.n"
	 * StringUtils.compose([null, "a", "n"], ".") = "a.n"
	 * StringUtils.compose(["", "a", "n"], ".")   = "a.n"
	 * StringUtils.compose(["h", "", "n"], ".")   = "h.n"
	 * StringUtils.compose(["  ", "a", "n"], ".") = "  .a.n"
	 * </pre>
	 * 
	 * @param strArray ¹®ÀÚ¿­ ¹è¿­
	 * @param separator ±¸ºÐÀÚ
	 * @return ±¸ºÐÀÚ·Î °áÇÕÇÑ ¹®ÀÚ¿­
	 */
	public static String compose(String[] strArray, char separator) {
		StringBuilder sb = new StringBuilder();
		if (strArray != null) {
			for (int i = 0; i < strArray.length; i++) {
				if (StringUtils.isEmpty(strArray[i])) {
					sb.append(EMPTY);
				} else {
					if (sb.length() > 0) {
						sb.append(separator);
					}
					sb.append(strArray[i]);
				}
			}
		}
		return sb.toString();
	}
	
	/**
	 * <p>¹®ÀÚ¿­ ¹è¿­À» ÇÏ³ªÀÇ ¹®ÀÚ¿­·Î °áÇÕ½ÃÅ²´Ù.</p>
	 * <p>¹è¿­ÀÇ ¹®ÀÚ¿­ Áß¿¡ <code>null</code>°ú °ø¹é("")Àº ¹«½ÃÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.compose(null, *)               = ""
	 * StringUtils.compose(["h", "a", "n"], ".")  = "h.a.n"
	 * StringUtils.compose([null, "a", "n"], ".") = "a.n"
	 * StringUtils.compose(["", "a", "n"], ".")   = "a.n"
	 * StringUtils.compose(["h", "", "n"], ".")   = "h.n"
	 * StringUtils.compose(["  ", "a", "n"], ".") = "  .a.n"
	 * </pre>
	 * 
	 * @param strArray ¹®ÀÚ¿­ ¹è¿­
	 * @param separator ±¸ºÐÀÚ
	 * @return ±¸ºÐÀÚ·Î °áÇÕÇÑ ¹®ÀÚ¿­
	 */
	public static String compose(String[] strArray, String separator) {
		StringBuilder sb = new StringBuilder();
		if (strArray != null) {
			for (int i = 0; i < strArray.length; i++) {
				if (StringUtils.isEmpty(strArray[i])) {
					sb.append(EMPTY);
				} else {
					if (sb.length() > 0) {
						sb.append(separator);
					}
					sb.append(strArray[i]);
				}
			}
		}
		return sb.toString();
	}
	
	/**
	 * <p>¹®ÀÚ¿­ ¹è¿­À» ÇÏ³ªÀÇ ¹®ÀÚ¿­·Î °áÇÕ½ÃÅ²´Ù.</p>
	 * <p>¹è¿­ÀÇ ¹®ÀÚ¿­ Áß¿¡ <code>null</code>°ú °ø¹é("")µµ Æ÷ÇÔÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.join(null, *)               = ""
	 * StringUtils.join(["h", "a", "n"], '-')  = "h-a-n"
	 * StringUtils.join([null, "a", "n"], '-') = "-a-n"
	 * StringUtils.join(["", "a", "n"], '-')   = "-a-n"
	 * StringUtils.join(["h", "", "n"], '-')   = "h--n"
	 * StringUtils.join(["  ", "a", "n"], '-') = "  -a-n"
	 * </pre>
	 * 
	 * @param strArray ¹®ÀÚ¿­ ¹è¿­
	 * @param separator ±¸ºÐÀÚ
	 * @return ±¸ºÐÀÚ·Î °áÇÕÇÑ ¹®ÀÚ¿­
	 */
	public static String join(String[] strArray, char separator) {
		StringBuilder sb = new StringBuilder();
		if (strArray != null) {
			boolean isFirst = true;
			for (int i = 0; i < strArray.length; i++) {
				if (isFirst) {
					isFirst = false;
				} else {
					sb.append(separator);
				}
				if (StringUtils.isEmpty(strArray[i])) {
					sb.append(EMPTY);
				} else {
					sb.append(strArray[i]);
				}
			}
		}
		return sb.toString();
	}
	
	/**
	 * <p>¹®ÀÚ¿­ ¹è¿­À» ÇÏ³ªÀÇ ¹®ÀÚ¿­·Î °áÇÕ½ÃÅ²´Ù.</p>
	 * <p>¹è¿­ÀÇ ¹®ÀÚ¿­ Áß¿¡ <code>null</code>°ú °ø¹é("")µµ Æ÷ÇÔÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.join(null, *)               = ""
	 * StringUtils.join(["h", "a", "n"], "-")  = "h-a-n"
	 * StringUtils.join([null, "a", "n"], "-") = "-a-n"
	 * StringUtils.join(["", "a", "n"], "-")   = "-a-n"
	 * StringUtils.join(["h", "", "n"], "-")   = "h--n"
	 * StringUtils.join(["  ", "a", "n"], "-") = "  -a-n"
	 * </pre>
	 * 
	 * @param strArray ¹®ÀÚ¿­ ¹è¿­
	 * @param separator ±¸ºÐÀÚ
	 * @return ±¸ºÐÀÚ·Î °áÇÕÇÑ ¹®ÀÚ¿­
	 */
	public static String join(String[] strArray, String separator) {
		StringBuilder sb = new StringBuilder();
		if (strArray != null) {
			boolean isFirst = true;
			for (int i = 0; i < strArray.length; i++) {
				if (isFirst) {
					isFirst = false;
				} else {
					sb.append(separator);
				}
				if (StringUtils.isEmpty(strArray[i])) {
					sb.append(EMPTY);
				} else {
					sb.append(strArray[i]);
				}
			}
		}
		return sb.toString();
	}
	
	/**
	 * <p>¹®ÀÚ¿­À» ±¸ºÐÀÚ·Î ³ª´©¾î¼­, ¹®ÀÚ¿­ ¹è¿­·Î ¸¸µç´Ù.</p>
	 * <p>¹è¿­ÀÇ ¹®ÀÚ¿­ Áß¿¡ <code>null</code>°ú °ø¹é("")µµ Æ÷ÇÔÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.split("h-a-n", '-') = ["h", "a", "n"]
	 * StringUtils.split("h--n", '-')  = ["h", "", "n"]
	 * StringUtils.split(null, *)      = null
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @param separator ±¸ºÐÀÚ
	 * @return ±¸ºÐÀÚ·Î ³ª´©¾îÁø ¹®ÀÚ¿­ ¹è¿­
	 */
	public static String[] split(String str, char separator) {
		return split(str, new String(new char[]{separator}));
	}
	
	/**
	 * <p>¹®ÀÚ¿­À» ±¸ºÐÀÚ·Î ³ª´©¾î¼­, ¹®ÀÚ¿­ ¹è¿­·Î ¸¸µç´Ù.</p>
	 * <p>¹è¿­ÀÇ ¹®ÀÚ¿­ Áß¿¡ <code>null</code>°ú °ø¹é("")µµ Æ÷ÇÔÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.split("h-a-n", "-") = ["h", "a", "n"]
	 * StringUtils.split("h--n", "-")  = ["h", "", "n"]
	 * StringUtils.split(null, *)      = null
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @param separator ±¸ºÐÀÚ
	 * @return ±¸ºÐÀÚ·Î ³ª´©¾îÁø ¹®ÀÚ¿­ ¹è¿­
	 */
	public static String[] split(String str, String separator) {
		if (str == null) {
			return null;
		}
		StrTokenizer tokenizer = new StrTokenizer(str, separator);
		return tokenizer.toArray();
	}
	
	// ----------------------------------------------------------------------
	// ¹®ÀÚ¿­ ÀÚ¸£±â
	// ----------------------------------------------------------------------
	/**
	 * <p>¹®ÀÚ¿­(String)À» ÇØ´ç ±æÀÌ(<code>length</code>) ¸¸Å­, ¿ÞÂÊºÎÅÍ ÀÚ¸¥´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.left(null, *)    = null
	 * StringUtils.left(*, -length) = ""
	 * StringUtils.left("", *)      = *
	 * StringUtils.left("han", 0)   = ""
	 * StringUtils.left("han", 1)   = "h"
	 * StringUtils.left("han", 11)  = "han"
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @param length ±æÀÌ
	 * @return
	 */
	public static String left(String str, int length) {
		if (str == null) {
			return null;
		}
		if (length < 0) {
			return EMPTY;
		}
		if (str.length() <= length) {
			return str;
		}
		return str.substring(0, length);
	}
	
	/**
	 * <p>¹®ÀÚ¿­(String)À» ÇØ´ç ±æÀÌ(<code>length</code>) ¸¸Å­, ¿À¸¥ÂÊºÎÅÍ ÀÚ¸¥´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.right(null, *)    = null
	 * StringUtils.right(*, -length) = ""
	 * StringUtils.right("", *)      = *
	 * StringUtils.right("han", 0)   = ""
	 * StringUtils.right("han", 1)   = "n"
	 * StringUtils.right("han", 11)  = "han"
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @param length ±æÀÌ
	 * @return
	 */
	public static String right(String str, int length) {
		if (str == null) {
			return null;
		}
		if (length < 0) {
			return EMPTY;
		}
		if (str.length() <= length) {
			return str;
		}
		return str.substring(str.length() - length);
	}
	
	/**
	 * <p>¹®ÀÚ¿­(String)À» ½ÃÀÛ À§Ä¡(<code>beginIndex</code>)ºÎÅÍ ±æÀÌ( <code>length</code>) ¸¸Å­ ÀÚ¸¥´Ù.</p>
	 * 
	 * <p>½ÃÀÛ À§Ä¡(<code>beginIndex</code>)°¡ À½¼öÀÏ °æ¿ì´Â 0À¸·Î ÀÚµ¿ º¯È¯µÈ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.mid(null, *, *)    = null
	 * StringUtils.mid(*, *, -length) = ""
	 * StringUtils.mid("han", 0, 1)   = "h"
	 * StringUtils.mid("han", 0, 11)  = "han"
	 * StringUtils.mid("han", 2, 3)   = "n"
	 * StringUtils.mid("han", -2, 3)  = "han"
	 * </pre> 
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @param beginIndex À§Ä¡(À½¼öÀÏ °æ¿ì´Â 0À¸·Î ÀÚµ¿ º¯È¯µÈ´Ù.)
	 * @param length ±æÀÌ
	 * @return
	 */
	public static String mid(String str, int beginIndex, int length) {
		if (str == null) {
			return null;
		}
		if (length < 0 || beginIndex > str.length()) {
			return EMPTY;
		}
		if (beginIndex < 0) {
			beginIndex = 0;
		}
		if (str.length() <= (beginIndex + length)) {
			return str.substring(beginIndex);
		}
		return str.substring(beginIndex, beginIndex + length);
	}
	
	/**
	 * <p>½ÃÀÛ ÀÎµ¦½ººÎÅÍ ¹®ÀÚ¿­À» ÀÚ´Â´Ù.</p>
	 * <p>½ÃÀÛ ÀÎµ¦½º°¡ 0º¸´Ù ÀÛ°Å³ª, ¹®ÀÚ¿­ÀÇ ÃÑ±æÀÌº¸´Ù Å©¸é °ø¹é("")À» ¹ÝÈ¯ÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.substring(null, *)    = null
	 * StringUtils.substring("", *)      = ""
	 * StringUtils.substring("han", 1)   = "an"
	 * StringUtils.substring("han", 615) = ""
	 * StringUtils.substring("han", -1)  = ""
	 * </pre> 
	 * 
	 * @param str
	 * @param beginIndex ½ÃÀÛ ÀÎµ¦½º(0ºÎÅÍ ½ÃÀÛ)
	 * @return
	 */
	public static String substring(String str, int beginIndex) {
		if (str == null){
			return null;
		}
		
		if (beginIndex < 0) {
			return EMPTY;
		}
		
		if (beginIndex > str.length()) {
			return EMPTY;
		}
		
		return str.substring(beginIndex);
	}


	/**
	 * <p>½ÃÀÛ ÀÎµ¦½ººÎÅÍ ³¡ ÀÎµ¦½º±îÁö ¹®ÀÚ¿­À» ÀÚ´Â´Ù.</p>
	 * <p>½ÃÀÛ ÀÎµ¦½º¶Ç´Â ³¡ ÀÎµ¦½º°¡  0º¸´Ù ÀÛÀ¸¸é °ø¹é("")À» ¹ÝÈ¯ÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.substring(null, *, *)    = null
	 * StringUtils.substring("", *, *)      = ""
	 * StringUtils.substring("han", 1, 2)   = "a"
	 * StringUtils.substring("han", 1, 3)   = "an"
	 * StringUtils.substring("han", 1, 615) = "an"
	 * StringUtils.substring("han", -1, *)  = ""
	 * StringUtils.substring("han", *, -1)  = ""
	 * </pre> 
	 * 
	 * @param str
	 * @param beginIndex
	 * @param endIndex
	 * @return
	 */
	public static String substring(String str, int beginIndex, int endIndex) {
		if (str == null){
			return null;
		}
		
		if (beginIndex < 0 || endIndex < 0) {
			return EMPTY;
		}
		
		if (endIndex > str.length()) {
			endIndex = str.length();
		}
		
		if (beginIndex > endIndex || beginIndex > str.length()) {
			return EMPTY;
		}
		
		return str.substring(beginIndex, endIndex);
	}
	
	
	/**
	 * <p>Ã³À½ ¹ß°ßÇÑ ±¸ºÐÀÚÀÇ À§Ä¡±îÁö ¹®ÀÚ¿­À» ÀÚ¸¥´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.substringBefore(null, *)       = null
	 * StringUtils.substringBefore("", *)         = ""
	 * StringUtils.substringBefore("han", null)   = "han"
	 * StringUtils.substringBefore("han", "")     = ""
	 * StringUtils.substringBefore("hanhan", "a") = "h"
	 * StringUtils.substringBefore("hanhan", "g") = "hanhan"
	 * </pre> 
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @param separator ±¸ºÐÀÚ
	 * @return
	 */
	public static String substringBefore(String str, String separator) {
		if (isEmpty(str) || separator == null) {
			return str;
		}
        if (separator.length() == 0) {
            return EMPTY;
        }
		int endIndex = str.indexOf(separator);
		if (endIndex == INDEX_NOT_FOUND) {
			return str;
		}
		return str.substring(0, endIndex);
	}
	
	
	/**
	 * <p>¸¶Áö¸·À¸·Î ¹ß°ßÇÑ ±¸ºÐÀÚÀÇ À§Ä¡±îÁö ¹®ÀÚ¿­À» ÀÚ¸¥´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.substringBeforeLast(null, *)       = null
	 * StringUtils.substringBeforeLast("", *)         = ""
	 * StringUtils.substringBeforeLast("han", null)   = "han"
	 * StringUtils.substringBeforeLast("han", "")     = "han"
	 * StringUtils.substringBeforeLast("hanhan", "a") = "hanh"
	 * StringUtils.substringBeforeLast("hanhan", "g") = "hanhan"
	 * </pre> 
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @param separator ±¸ºÐÀÚ
	 * @return
	 */
	public static String substringBeforeLast(String str, String separator) {
		if (isEmpty(str) || isEmpty(separator)) {
			return str;
		}
		int endIndex = str.lastIndexOf(separator);
		if (endIndex == INDEX_NOT_FOUND) {
			return str;
		}
		return str.substring(0, endIndex);
	}

	
	/**
	 * <p>Ã³À½ ¹ß°ßÇÑ ±¸ºÐÀÚÀÇ À§Ä¡ ´ÙÀ½ºÎÅÍ ¹®ÀÚ¿­À» ÀÚ¸¥´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.substringAfter(null, *)       = null
	 * StringUtils.substringAfter("", *)         = ""
	 * StringUtils.substringAfter("han", null)   = ""
	 * StringUtils.substringAfter("han", "")     = "han"
	 * StringUtils.substringAfter("hanhan", "a") = "nhan"
	 * StringUtils.substringAfter("hanhan", "g") = ""
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @param separator ±¸ºÐÀÚ
	 * @return
	 */
	public static String substringAfter(String str, String separator) {
		if (isEmpty(str)) {
			return str;
		}
		if (separator == null) {
			return EMPTY;
		}
		int beginIndex = str.indexOf(separator);
		if (beginIndex == INDEX_NOT_FOUND) {
			return EMPTY;
		}
		beginIndex = beginIndex + separator.length();
		if (beginIndex == str.length()) {
			return EMPTY;
		}
		return str.substring(beginIndex);
	}
	
	/**
	 * <p>¸¶Áö¸·À¸·Î ¹ß°ßÇÑ ±¸ºÐÀÚÀÇ À§Ä¡ ´ÙÀ½ºÎÅÍ ¹®ÀÚ¿­À» ÀÚ¸¥´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.substringAfterLast(null, *)       = null
	 * StringUtils.substringAfterLast("", *)         = ""
	 * StringUtils.substringAfterLast("han", null)   = ""
	 * StringUtils.substringAfterLast("han",     "") = ""
	 * StringUtils.substringAfterLast("hanhan", "a") = "n"
	 * StringUtils.substringAfterLast("hanhan", "g") = ""
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @param separator ±¸ºÐÀÚ
	 * @return
	 */
	public static String substringAfterLast(String str, String separator) {
		if (isEmpty(str)) {
			return str;
		}
		if (isEmpty(separator)) {
			return EMPTY;
		}
		int beginIndex = str.lastIndexOf(separator);
		if (beginIndex == INDEX_NOT_FOUND) {
			return EMPTY;
		}
		beginIndex = beginIndex + separator.length();
		if (beginIndex == str.length()) {
			return EMPTY;
		}
		return str.substring(beginIndex);
	}
	
	/**
	 * <p>½ÃÀÛ ¹®ÀÚºÎÅÍ ³¡ ¹®ÀÚ¿­±îÁö ÀÚ¸¥´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.substringBetween(null, *, *)       = null
	 * StringUtils.substringBetween(*, null, *)       = null
	 * StringUtils.substringBetween(*, *, null)       = null
	 * StringUtils.substringBetween("h<a>n", "<", ">") = "a"
	 * StringUtils.substringBetween("h<a><b>n", "<", ">") = "a"
	 * </pre>
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @param separator ±¸ºÐÀÚ
	 * @return
	 * @since 1.1
	 */
    public static String substringBetween(String str, String open, String close) {
		if (str == null || open == null || close == null) {
			return null;
		}
		
		int start = str.indexOf(open);
		if (start != INDEX_NOT_FOUND) {
			int end = str.indexOf(close, start + open.length());
			if (end != INDEX_NOT_FOUND) {
				return str.substring(start + open.length(), end);
			} else {
				// ³¡ÀÌ ¾øÀ¸¸é nullÀÌ ÁÁÀ»±î, ³¡±îÁö°¡ ÁÁÀ»±î...
			}
		}
		return null;
	}
    
    /**
     * <p>ÀÔ·ÂÇÑ ¹®ÀÚ¿­À» ÇÑÁÙÀÇ ÃÖ´ë ±æÀÌ¸¸Å­, ¿©·¯ ÁÙ·Î ³ª´©¾î ¹ÝÈ¯ÇÑ´Ù.</p>
     * <p>°ø¹é(" ")À» ±âÁØÀ¸·Î ÁÙ ¹Ù²ÞÀ» ½ÃµµÇÑ´Ù.</p>
     * 
     * @param str
     * @param maxLineLength ÇÑÁÙÀÇ ÃÖ´ë ±æÀÌ
     * @return
     */
    public static List<String> wrap(String str, int maxLineLength) {
    	if (str == null) {
    		return null;
    	}
    	List<String> lines = new ArrayList<String>();
        if (str.length() <= maxLineLength || str.indexOf(' ') == INDEX_NOT_FOUND) {
        	// ÀüÃ¼ ±æÀÌ°¡ ÃÖ´ë ±æÀÌº¸´Ù Âª°Å³ª, ±¸ºÐÇÒ¼ö ÀÖ´Â Á¶°ÇÀÌ ¾ÈµÇ¸é ±×´ë·Î ¹ÝÈ¯ÇÑ´Ù.
        	lines.add(str);
            return lines;
        }
        
        StringBuilder sb = new StringBuilder();
        StringTokenizer tokenzier = new StringTokenizer(str, " ");
        sb.append(tokenzier.nextToken());
        while (tokenzier.hasMoreTokens()) {
            String token = tokenzier.nextToken();
            if ( (sb.length() + token.length() + 1) > maxLineLength) {
                lines.add(sb.toString());
                sb.setLength(0);
                sb.append(token);
            } else {
                sb.append(" ");
                sb.append(token);
            }
        }

        if (sb.toString().trim().length() > 0) {
            lines.add(sb.toString());
        }
        return lines;
    }
	
	/**
	 * <p>¹®ÀÚ¿­ÀÌ ÇØ´ç ±æÀÌº¸´Ù Å©¸é, ÀÚ¸¥ ÈÄ ÁÙÀÓ¸»À» ºÙ¿©ÁØ´Ù.</p>
	 * <p>±æÀÌ´Â ±âº»¹®ÀÚµé(¿µ¾î/¼ýÀÚµî)ÀÌ 1À¸·Î, ´Ù±¹¾î(ÇÑ±Ûµî)ÀÌ¸é 2·Î °è»êÇÑ´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.curtail(null, *, *) = null
	 * StringUtils.curtail("abcdefghijklmnopqr", 10, null) = "abcdefghij"
	 * StringUtils.curtail("abcdefghijklmnopqr", 10, "..") = "abcdefgh.."
	 * StringUtils.curtail("ÇÑ±ÛÀ» »ç¶ûÇÕ½Ã´Ù.", 10, null)   = "ÇÑ±ÛÀ» »ç¶û"
	 * StringUtils.curtail("ÇÑ±ÛÀ» »ç¶ûÇÕ½Ã´Ù.", 10, "..")   = "ÇÑ±ÛÀ» »ç.."
	 * </pre>
	 * 
	 * 
	 * @param str ¹®ÀÚ¿­
	 * @param size ±æÀÌ(byte ±æÀÌ)
	 * @param tail ÁÙÀÓ¸»
	 * @return
	 */
	public static String curtail(String str, int size, String tail) {
		if (str == null) {
			return null;
		}
		int strLen = str.length();
		int tailLen = (tail != null) ? tail.length() : 0;
		int maxLen = size - tailLen;
		int curLen = 0;
		int index = 0;
		for (; index < strLen && curLen < maxLen; index++) {
			if (Character.getType(str.charAt(index)) == Character.OTHER_LETTER) {
				curLen++;
			}
			curLen++;
		}
		
		if (index == strLen) {
			return str;
		} else {
			StringBuilder result = new StringBuilder(size);
			result.append(str.substring(0, index));
			if (tail != null) {
				result.append(tail);	
			}
			return result.toString();
		}
	}
	
	// ----------------------------------------------------------------------
	// ÆÐµù
	// ----------------------------------------------------------------------
	/**
	 * <p>¿ÞÂÊºÎÅÍ Å©±â¸¸Å­ ÆÐµù¹®ÀÚ·Î Ã¤¿î´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.leftPad("han", 5, " ")    = "  han"
	 * StringUtils.leftPad("han", 5, "123")  = "12han"
	 * StringUtils.leftPad("han", 10, "123") = "1231231han"
	 * StringUtils.leftPad("han", -1, " ")   = "han"
	 * </pre>
	 * 
	 * @param str
	 * @param size Å©±â
	 * @param padStr ÆÐµù¹®ÀÚ
	 * @return
	 */
	public static String leftPad(String str, int size, String padStr) {
		if (str == null) {
			return null;
		}
		if (isEmpty(padStr)) {
			padStr = " "; //$NON-NLS-1$
		}
		int strLen = str.length();
		int padStrLen = padStr.length();
		int padLen = size - strLen;
		if (padLen <= 0) {
			// ÆÐµùÇÒ ÇÊ¿ä°¡ ¾øÀ½
			return str;
		}
		
		StringBuilder result = new StringBuilder();
		if (padLen == padStrLen) {
			result.append(padStr);
			result.append(str);
		} else if (padLen < padStrLen) {
			result.append(padStr.substring(0, padLen));
			result.append(str);
		} else {
			char[] padding = padStr.toCharArray();
			for (int i = 0; i < padLen; i++) {
				result.append(padding[ i % padStrLen]);
			}
			result.append(str);
		}
		return result.toString();
	}
	
	/**
	 * <p>¿À¸¥ÂÊºÎÅÍ Å©±â¸¸Å­ ÆÐµù¹®ÀÚ·Î Ã¤¿î´Ù.</p>
	 * 
	 * <pre>
	 * StringUtils.rightPad("han", 5, " ")    = "han  "
	 * StringUtils.rightPad("han", 5, "123")  = "han12"
	 * StringUtils.rightPad("han", 10, "123") = "han1231231"
	 * StringUtils.rightPad("han", -1, " ")   = "han"
	 * </pre>
	 * 
	 * @param str
	 * @param size Å©±â
	 * @param padStr ÆÐµù¹®ÀÚ
	 * @return
	 */
	public static String rightPad(String str, int size, String padStr) {
		if (str == null) {
			return null;
		}
		if (isEmpty(padStr)) {
			padStr = " "; //$NON-NLS-1$
		}
		int strLen = str.length();
		int padStrLen = padStr.length();
		int padLen = size - strLen;
		if (padLen <= 0) {
			// ÆÐµùÇÒ ÇÊ¿ä°¡ ¾øÀ½
			return str;
		}
		
		StringBuilder result = new StringBuilder();
		if (padLen == padStrLen) {
			result.append(str);
			result.append(padStr);
		} else if (padLen < padStrLen) {
			result.append(str);
			result.append(padStr.substring(0, padLen));
		} else {
			result.append(str);
			char[] padding = padStr.toCharArray();
			for (int i = 0; i < padLen; i++) {
				result.append(padding[ i % padStrLen]);
			}
		}
		return result.toString();
	}
}

