content: /*
   * Copyright 2013-2023 the original author or authors.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      https://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.alibaba.cloud.nacos.utils;
  
  /**
   * StringUtils. copy from apache common-lang3.
   *
   * @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
   */
  public final class StringUtils {
  
  	/**
  	 * The empty String {@code ""}.
  	 *
  	 * @since 2.0
  	 */
  	public static final String EMPTY = "";
  
  	/**
  	 * Represents a failed index search.
  	 * @since 2.1
  	 */
  	public static final int INDEX_NOT_FOUND = -1;
  
  	private StringUtils() {
  	}
  
  	/**
  	 * <p>
  	 * Checks if a CharSequence is empty ("") or null.
  	 * </p>
  	 *
  	 * <pre>
  	 * StringUtils.isEmpty(null)      = true
  	 * StringUtils.isEmpty("")        = true
  	 * StringUtils.isEmpty(" ")       = false
  	 * StringUtils.isEmpty("bob")     = false
  	 * StringUtils.isEmpty("  bob  ") = false
  	 * </pre>
  	 *
  	 * <p>
  	 * NOTE: This method changed in Lang version 2.0. It no longer trims the CharSequence.
  	 * That functionality is available in isBlank().
  	 * </p>
  	 * @param cs the CharSequence to check, may be null
  	 * @return {@code true} if the CharSequence is empty or null
  	 * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
  	 */
  	public static boolean isEmpty(final CharSequence cs) {
  		return cs == null || cs.length() == 0;
  	}
  
  	/**
  	 * <p>
  	 * Checks if a CharSequence is not empty ("") and not null.
  	 * </p>
  	 *
  	 * <pre>
  	 * StringUtils.isNotEmpty(null)      = false
  	 * StringUtils.isNotEmpty("")        = false
  	 * StringUtils.isNotEmpty(" ")       = true
  	 * StringUtils.isNotEmpty("bob")     = true
  	 * StringUtils.isNotEmpty("  bob  ") = true
  	 * </pre>
  	 * @param cs the CharSequence to check, may be null
  	 * @return {@code true} if the CharSequence is not empty and not null
  	 * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
  	 */
  	public static boolean isNotEmpty(final CharSequence cs) {
  		return !isEmpty(cs);
  	}
  
  	/**
  	 * <p>
  	 * Checks if a CharSequence is whitespace, empty ("") or null.
  	 * </p>
  	 *
  	 * <pre>
  	 * StringUtils.isBlank(null)      = true
  	 * StringUtils.isBlank("")        = true
  	 * StringUtils.isBlank(" ")       = true
  	 * StringUtils.isBlank("bob")     = false
  	 * StringUtils.isBlank("  bob  ") = false
  	 * </pre>
  	 * @param cs the CharSequence to check, may be null
  	 * @return {@code true} if the CharSequence is null, empty or whitespace
  	 */
  	public static boolean isBlank(final CharSequence cs) {
  		if (cs == null || cs.length() == 0) {
  			return true;
  		}
  		int strLen = cs.length();
  		for (int i = 0; i < strLen; i++) {
  			if (!Character.isWhitespace(cs.charAt(i))) {
  				return false;
  			}
  		}
  		return true;
  	}
  
  	/**
  	 * <p>
  	 * Checks if a CharSequence is not empty (""), not null and not whitespace only.
  	 * </p>
  	 *
  	 * <p>
  	 * Whitespace is defined by {@link Character#isWhitespace(char)}.
  	 * </p>
  	 *
  	 * <pre>
  	 * StringUtils.isNotBlank(null)      = false
  	 * StringUtils.isNotBlank("")        = false
  	 * StringUtils.isNotBlank(" ")       = false
  	 * StringUtils.isNotBlank("bob")     = true
  	 * StringUtils.isNotBlank("  bob  ") = true
  	 * </pre>
  	 * @param cs the CharSequence to check, may be null
  	 * @return {@code true} if the CharSequence is not empty and not null and not
  	 * whitespace only
  	 * @since 2.0
  	 * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
  	 */
  	public static boolean isNotBlank(final CharSequence cs) {
  		return !isBlank(cs);
  	}
  
  	// Trim
  	// -----------------------------------------------------------------------
  
  	/**
  	 * <p>
  	 * Removes control characters (char &lt;= 32) from both ends of this String, handling
  	 * {@code null} by returning {@code null}.
  	 * </p>
  	 *
  	 * <p>
  	 * The String is trimmed using {@link String#trim()}. Trim removes start and end
  	 * characters &lt;= 32.
  	 * </p>
  	 *
  	 * <pre>
  	 * StringUtils.trim(null)          = null
  	 * StringUtils.trim("")            = ""
  	 * StringUtils.trim("     ")       = ""
  	 * StringUtils.trim("abc")         = "abc"
  	 * StringUtils.trim("    abc    ") = "abc"
  	 * </pre>
  	 * @param str the String to be trimmed, may be null
  	 * @return the trimmed string, {@code null} if null String input
  	 */
  	public static String trim(final String str) {
  		return str == null ? null : str.trim();
  	}
  
  	// Equals
  	// -----------------------------------------------------------------------
  
  	/**
  	 * <p>
  	 * Compares two CharSequences, returning {@code true} if they represent equal
  	 * sequences of characters.
  	 * </p>
  	 *
  	 * <p>
  	 * {@code null}s are handled without exceptions. Two {@code null} references are
  	 * considered to be equal. The comparison is case sensitive.
  	 * </p>
  	 *
  	 * <pre>
  	 * StringUtils.equals(null, null)   = true
  	 * StringUtils.equals(null, "abc")  = false
  	 * StringUtils.equals("abc", null)  = false
  	 * StringUtils.equals("abc", "abc") = true
  	 * StringUtils.equals("abc", "ABC") = false
  	 * </pre>
  	 * @param cs1 the first CharSequence, may be {@code null}
  	 * @param cs2 the second CharSequence, may be {@code null}
  	 * @return {@code true} if the CharSequences are equal (case-sensitive), or both
  	 * {@code null}
  	 * @see Object#equals(Object)
  	 */
  	public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
  		if (cs1 == cs2) {
  			return true;
  		}
  		if (cs1 == null || cs2 == null) {
  			return false;
  		}
  		if (cs1 instanceof String && cs2 instanceof String) {
  			return cs1.equals(cs2);
  		}
  		return StringUtils.regionMatches(cs1, false, 0, cs2, 0,
  				Math.max(cs1.length(), cs2.length()));
  	}
  
  	/**
  	 * Green implementation of regionMatches.
  	 * @param cs the {@code CharSequence} to be processed
  	 * @param ignoreCase whether or not to be case insensitive
  	 * @param thisStart the index to start on the {@code cs} CharSequence
  	 * @param substring the {@code CharSequence} to be looked for
  	 * @param start the index to start on the {@code substring} CharSequence
  	 * @param length character length of the region
  	 * @return whether the region matched
  	 */
  	public static boolean regionMatches(final CharSequence cs, final boolean ignoreCase,
  			final int thisStart, final CharSequence substring, final int start,
  			final int length) {
  		if (cs instanceof String && substring instanceof String) {
  			return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring,
  					start, length);
  		}
  		int index1 = thisStart;
  		int index2 = start;
  		int tmpLen = length;
  
  		while (tmpLen-- > 0) {
  			final char c1 = cs.charAt(index1++);
  			final char c2 = substring.charAt(index2++);
  
  			if (c1 == c2) {
  				continue;
  			}
  
  			if (!ignoreCase) {
  				return false;
  			}
  
  			// The same check as in String.regionMatches():
  			if (Character.toUpperCase(c1) != Character.toUpperCase(c2)
  					&& Character.toLowerCase(c1) != Character.toLowerCase(c2)) {
  				return false;
  			}
  		}
  
  		return true;
  	}
  
  	/**
  	 * <p>
  	 * Gets the substring after the first occurrence of a separator. The separator is not
  	 * returned.
  	 * </p>
  	 *
  	 * <p>
  	 * A <code>null</code> string input will return <code>null</code>. An empty ("")
  	 * string input will return the empty string. A <code>null</code> separator will
  	 * return the empty string if the input string is not <code>null</code>.
  	 * </p>
  	 *
  	 * <p>
  	 * If nothing is found, the empty string is returned.
  	 * </p>
  	 *
  	 * <pre>
  	 * StringUtils.substringAfter(null, *)      = null
  	 * StringUtils.substringAfter("", *)        = ""
  	 * StringUtils.substringAfter(*, null)      = ""
  	 * StringUtils.substringAfter("abc", "a")   = "bc"
  	 * StringUtils.substringAfter("abcba", "b") = "cba"
  	 * StringUtils.substringAfter("abc", "c")   = ""
  	 * StringUtils.substringAfter("abc", "d")   = ""
  	 * StringUtils.substringAfter("abc", "")    = "abc"
  	 * </pre>
  	 * @param str the String to get a substring from, may be null
  	 * @param separator the String to search for, may be null
  	 * @return the substring after the first occurrence of the separator,
  	 * <code>null</code> if null String input
  	 * @since 2.0
  	 */
  	public static String substringAfter(String str, String separator) {
  		if (isEmpty(str)) {
  			return str;
  		}
  		if (separator == null) {
  			return EMPTY;
  		}
  		int pos = str.indexOf(separator);
  		if (pos == INDEX_NOT_FOUND) {
  			return EMPTY;
  		}
  		return str.substring(pos + separator.length());
  	}
  
  	// Substring between
  	// -----------------------------------------------------------------------
  	/**
  	 * <p>
  	 * Gets the String that is nested in between two instances of the same String.
  	 * </p>
  	 *
  	 * <p>
  	 * A <code>null</code> input String returns <code>null</code>. A <code>null</code> tag
  	 * returns <code>null</code>.
  	 * </p>
  	 *
  	 * <pre>
  	 * StringUtils.substringBetween(null, *)            = null
  	 * StringUtils.substringBetween("", "")             = ""
  	 * StringUtils.substringBetween("", "tag")          = null
  	 * StringUtils.substringBetween("tagabctag", null)  = null
  	 * StringUtils.substringBetween("tagabctag", "")    = ""
  	 * StringUtils.substringBetween("tagabctag", "tag") = "abc"
  	 * </pre>
  	 * @param str the String containing the substring, may be null
  	 * @param tag the String before and after the substring, may be null
  	 * @return the substring, <code>null</code> if no match
  	 * @since 2.0
  	 */
  	public static String substringBetween(String str, String tag) {
  		return substringBetween(str, tag, tag);
  	}
  
  	/**
  	 * <p>
  	 * Gets the String that is nested in between two Strings. Only the first match is
  	 * returned.
  	 * </p>
  	 *
  	 * <p>
  	 * A <code>null</code> input String returns <code>null</code>. A <code>null</code>
  	 * open/close returns <code>null</code> (no match). An empty ("") open and close
  	 * returns an empty string.
  	 * </p>
  	 *
  	 * <pre>
  	 * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
  	 * StringUtils.substringBetween(null, *, *)          = null
  	 * StringUtils.substringBetween(*, null, *)          = null
  	 * StringUtils.substringBetween(*, *, null)          = null
  	 * StringUtils.substringBetween("", "", "")          = ""
  	 * StringUtils.substringBetween("", "", "]")         = null
  	 * StringUtils.substringBetween("", "[", "]")        = null
  	 * StringUtils.substringBetween("yabcz", "", "")     = ""
  	 * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
  	 * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
  	 * </pre>
  	 * @param str the String containing the substring, may be null
  	 * @param open the String before the substring, may be null
  	 * @param close the String after the substring, may be null
  	 * @return the substring, <code>null</code> if no match
  	 * @since 2.0
  	 */
  	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);
  			}
  		}
  		return null;
  	}
  
  }
  