Skip to content

Commit

Permalink
Merge pull request #84 from kpartlow/master
Browse files Browse the repository at this point in the history
Added Instant Conversions
  • Loading branch information
jdereg committed Jan 26, 2024
2 parents 764be4f + 5d2e406 commit 38b9a4d
Show file tree
Hide file tree
Showing 25 changed files with 2,741 additions and 918 deletions.
4 changes: 2 additions & 2 deletions src/main/java/com/cedarsoftware/util/DateUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ private DateUtilities() {
* passed in, null will be returned.
*/
public static Date parseDate(String dateStr) {
if (StringUtilities.isEmpty(dateStr)) {
if (StringUtilities.isWhitespace(dateStr)) {
return null;
}
ZonedDateTime zonedDateTime = parseDate(dateStr, ZoneId.systemDefault(), true);
Expand Down Expand Up @@ -357,4 +357,4 @@ private static String stripBrackets(String input) {
}
return input.replaceAll("^\\[|\\]$", "");
}
}
}
280 changes: 239 additions & 41 deletions src/main/java/com/cedarsoftware/util/StringUtilities.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.cedarsoftware.util;

import java.io.UnsupportedEncodingException;
import java.util.Optional;
import java.util.Random;

/**
Expand Down Expand Up @@ -31,6 +32,8 @@ public final class StringUtilities
};
public static final String FOLDER_SEPARATOR = "/";

public static final String EMPTY = "";

/**
* <p>Constructor is declared private since all methods are static.</p>
*/
Expand All @@ -39,22 +42,124 @@ private StringUtilities()
super();
}

public static boolean equals(final String str1, final String str2)
{
if (str1 == null || str2 == null)
{
return str1 == str2;
/**
* Compares two CharSequences, returning {@code true} if they represent
* equal sequences of characters.
*
* <p>{@code null}s are handled without exceptions. Two {@code null}
* references are considered to be equal. The comparison is <strong>case-sensitive</strong>.</p>
*
* @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 #equalsIgnoreCase(CharSequence, CharSequence)
*/
public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
if (cs1 == cs2) {
return true;
}
if (cs1 == null || cs2 == null) {
return false;
}
if (cs1.length() != cs2.length()) {
return false;
}
if (cs1 instanceof String && cs2 instanceof String) {
return cs1.equals(cs2);
}
// Step-wise comparison
final int length = cs1.length();
for (int i = 0; i < length; i++) {
if (cs1.charAt(i) != cs2.charAt(i)) {
return false;
}
}
return str1.equals(str2);
return true;
}

public static boolean equalsIgnoreCase(final String s1, final String s2)
{
if (s1 == null || s2 == null)
{
return s1 == s2;
/**
* Compares two CharSequences, returning {@code true} if they represent
* equal sequences of characters, ignoring case.
*
* <p>{@code null}s are handled without exceptions. Two {@code null}
* references are considered equal. The comparison is <strong>case insensitive</strong>.</p>
*
* @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-insensitive), or both {@code null}
* @see #equals(CharSequence, CharSequence)
*/
public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) {
if (cs1 == cs2) {
return true;
}
if (cs1 == null || cs2 == null) {
return false;
}
if (cs1.length() != cs2.length()) {
return false;
}
return regionMatches(cs1, true, 0, cs2, 0, cs1.length());
}

/**
* Green implementation of regionMatches.
*
* @param cs the {@link 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 {@link 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
*/
static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int thisStart,
final CharSequence substring, final int start, final int length) {
Convention.throwIfNull(cs, "cs to be processed cannot be null");
Convention.throwIfNull(substring, "substring cannot be null");

if (cs instanceof String && substring instanceof String) {
return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring, start, length);
}
return s1.equalsIgnoreCase(s2);
int index1 = thisStart;
int index2 = start;
int tmpLen = length;

// Extract these first so we detect NPEs the same as the java.lang.String version
final int srcLen = cs.length() - thisStart;
final int otherLen = substring.length() - start;

// Check for invalid parameters
if (thisStart < 0 || start < 0 || length < 0) {
return false;
}

// Check that the regions are long enough
if (srcLen < length || otherLen < length) {
return false;
}

while (tmpLen-- > 0) {
final char c1 = cs.charAt(index1++);
final char c2 = substring.charAt(index2++);

if (c1 == c2) {
continue;
}

if (!ignoreCase) {
return false;
}

// The real same check as in String.regionMatches():
final char u1 = Character.toUpperCase(c1);
final char u2 = Character.toUpperCase(c2);
if (u1 != u2 && Character.toLowerCase(u1) != Character.toLowerCase(u2)) {
return false;
}
}

return true;
}

public static boolean equalsWithTrim(final String s1, final String s2)
Expand All @@ -75,41 +180,89 @@ public static boolean equalsIgnoreCaseWithTrim(final String s1, final String s2)
return s1.trim().equalsIgnoreCase(s2.trim());
}

public static boolean isEmpty(final String s)
/**
* Checks if a CharSequence is empty (""), null, or only whitespace.
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if the CharSequence is empty or null
*/
public static boolean isEmpty(CharSequence cs)
{
return trimLength(s) == 0;
return isWhitespace(cs);
}

public static boolean hasContent(final String s)
{
return !(trimLength(s) == 0); // faster than returning !isEmpty()
/**
* Checks if a CharSequence is not empty (""), not null and not whitespace only.
*
* @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
*/
public static boolean isNotWhitespace(final CharSequence cs) {
return !isWhitespace(cs);
}

/**
* Use this method when you don't want a length check to
* throw a NullPointerException when
* Checks if a CharSequence is empty (""), null or whitespace only.
*
* @param s string to return length of
* @return 0 if string is null, otherwise the length of string.
* @param cs the CharSequence to check, may be null
* @return {@code true} if the CharSequence is null, empty or whitespace only
*/
public static int length(final String s)
{
return s == null ? 0 : s.length();
public static boolean isWhitespace(final CharSequence cs) {
final int strLen = length(cs);
if (strLen == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
return true;
}

/**
* Returns the length of the trimmed string. If the length is
* null then it returns 0.
* Checks if a CharSequence is not null, not empty (""), and not only whitespace.
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if the CharSequence is not empty and not null
*/
public static int trimLength(final String s)
{
return (s == null) ? 0 : s.trim().length();
public static boolean isNotEmpty(final CharSequence cs) {
return !isWhitespace(cs);
}

public static int lastIndexOf(String path, char ch)
{
if (path == null)
{
/**
* Checks if a CharSequence is not empty (""), not null and not whitespace only.
*
* @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
*/
public static boolean hasContent(final CharSequence cs) {
return !isWhitespace(cs);
}

/**
* Gets a CharSequence length or {@code 0} if the CharSequence is {@code null}.
*
* @param cs a CharSequence or {@code null}
* @return CharSequence length or {@code 0} if the CharSequence is {@code null}.
*/
public static int length(final CharSequence cs) {
return cs == null ? 0 : cs.length();
}

/**
* @param s a String or {@code null}
* @return the trimmed length of the String or 0 if the string is null.
*/
public static int trimLength(final String s) {
return trimToEmpty(s).length();
}


public static int lastIndexOf(String path, char ch) {
if (path == null) {
return -1;
}
return path.lastIndexOf(ch);
Expand Down Expand Up @@ -169,7 +322,7 @@ private static char convertDigit(int value)

public static int count(String s, char c)
{
return count (s, "" + c);
return count (s, EMPTY + c);
}

/**
Expand Down Expand Up @@ -268,11 +421,11 @@ public static String wildcardToRegexString(String wildcard)
public static int levenshteinDistance(CharSequence s, CharSequence t)
{
// degenerate cases s
if (s == null || "".equals(s))
if (s == null || EMPTY.equals(s))
{
return t == null || "".equals(t) ? 0 : t.length();
return t == null || EMPTY.equals(t) ? 0 : t.length();
}
else if (t == null || "".equals(t))
else if (t == null || EMPTY.equals(t))
{
return s.length();
}
Expand Down Expand Up @@ -329,11 +482,11 @@ else if (t == null || "".equals(t))
*/
public static int damerauLevenshteinDistance(CharSequence source, CharSequence target)
{
if (source == null || "".equals(source))
if (source == null || EMPTY.equals(source))
{
return target == null || "".equals(target) ? 0 : target.length();
return target == null || EMPTY.equals(target) ? 0 : target.length();
}
else if (target == null || "".equals(target))
else if (target == null || EMPTY.equals(target))
{
return source.length();
}
Expand Down Expand Up @@ -415,6 +568,7 @@ public static String getRandomString(Random random, int minLen, int maxLen)
{
StringBuilder s = new StringBuilder();
final int len = minLen + random.nextInt(maxLen - minLen + 1);

for (int i=0; i < len; i++)
{
s.append(getRandomChar(random, i == 0));
Expand All @@ -425,7 +579,7 @@ public static String getRandomString(Random random, int minLen, int maxLen)
public static String getRandomChar(Random random, boolean upper)
{
int r = random.nextInt(26);
return upper ? "" + (char)((int)'A' + r) : "" + (char)((int)'a' + r);
return upper ? EMPTY + (char)((int)'A' + r) : EMPTY + (char)((int)'a' + r);
}

/**
Expand Down Expand Up @@ -523,4 +677,48 @@ public static int hashCodeIgnoreCase(String s)
}
return hash;
}

/**
* Removes control characters (char &lt;= 32) from both
* ends of this String, handling {@code null} by returning
* {@code null}.
*
* <p>The String is trimmed using {@link String#trim()}.
* Trim removes start and end characters &lt;= 32.
*
* @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();
}

/**
* Trims a string, its null safe and null will return empty string here..
* @param value string input
* @return String trimmed string, if value was null this will be empty
*/
public static String trimToEmpty(String value) {
return value == null ? EMPTY : value.trim();
}

/**
* Trims a string, If the string trims to empty then we return null.
* @param value string input
* @return String, trimmed from value. If the value was empty we return null.
*/
public static String trimToNull(String value) {
final String ts = trim(value);
return isEmpty(ts) ? null : ts;
}

/**
* Trims a string, If the string trims to empty then we return the default.
* @param value string input
* @param defaultValue value to return on empty or null
* @return trimmed string, or defaultValue when null or empty
*/
public static String trimEmptyToDefault(String value, String defaultValue) {
return Optional.ofNullable(value).map(StringUtilities::trimToNull).orElse(defaultValue);
}
}
Loading

0 comments on commit 38b9a4d

Please sign in to comment.