From 5b83eb9358fea34692be7e712791d19fc64f352a Mon Sep 17 00:00:00 2001 From: Alex Chaffee Date: Sat, 29 Mar 2003 16:17:21 +0000 Subject: [PATCH] changed chomp() to match Perl deprecated chomp* methods in favor of new slice methods improved unit tests and documentation git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@137277 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/commons/lang/StringUtils.java | 189 +++++++++++++++--- .../apache/commons/lang/StringUtilsTest.java | 108 ++++++++-- 2 files changed, 255 insertions(+), 42 deletions(-) diff --git a/src/java/org/apache/commons/lang/StringUtils.java b/src/java/org/apache/commons/lang/StringUtils.java index 98f7ea8c6..1bc1f198d 100644 --- a/src/java/org/apache/commons/lang/StringUtils.java +++ b/src/java/org/apache/commons/lang/StringUtils.java @@ -78,7 +78,7 @@ import org.apache.commons.lang.exception.NestableRuntimeException; * @author Henning P. Schmiedehausen * @author Arun Mammen Thomas * @since 1.0 - * @version $Id: StringUtils.java,v 1.39 2003/03/25 00:15:58 scolebourne Exp $ + * @version $Id: StringUtils.java,v 1.40 2003/03/29 16:17:21 alex Exp $ */ public class StringUtils { @@ -820,36 +820,72 @@ public class StringUtils { // Chomping //-------------------------------------------------------------------------- - - /** - *

Remove the last newline, and everything after it from a String.

+ + /** + *

Remove one newline from end of a String if it's there, + * otherwise leave it alone. A newline is "\n", "\r", or "\r\n". + *

+ * Note that this behavior has changed from 1.0. It + * now more closely matches Perl chomp. For the previous behavior, + * use slice(String). * - * @param str String to chomp the newline from - * @return String without chomped newline + * @param str String to chomp a newline from + * @return String without newline * @throws NullPointerException if str is null */ public static String chomp(String str) { - return chomp(str, "\n"); - } - - /** - *

Remove the last value of a supplied String, and everything after - * it from a String.

- * - * @param str String to chomp from - * @param sep String to chomp - * @return String without chomped ending - * @throws NullPointerException if str or sep is null - */ - public static String chomp(String str, String sep) { - int idx = str.lastIndexOf(sep); - if (idx != -1) { - return str.substring(0, idx); - } else { + if (str.length() == 0) { return str; } + + if (str.length() == 1) { + if ("\r".equals(str) || "\n".equals(str)) { + return ""; + } + else { + return str; + } + } + + int lastIdx = str.length() - 1; + char last = str.charAt(lastIdx); + + if (last == '\n') { + if (str.charAt(lastIdx - 1) == '\r') { + lastIdx--; + } + } else if (last == '\r') { + + } else { + lastIdx++; + } + return str.substring(0, lastIdx); } - + + /** + *

Remove one string (the separator) from the end of another + * string if it's there, otherwise leave it alone. + *

+ * + * Note that this behavior has changed from 1.0. It + * now more closely matches Perl chomp. For the previous behavior, + * use slice(String,String). + * + * @param str string to chomp from + * @param separator separator string + * @return String without trailing separator + * @throws NullPointerException if str is null + */ + public static String chomp(String str, String separator) { + if (str.length() == 0) { + return str; + } + if (str.endsWith(separator)) { + return str.substring(0, str.length() - separator.length()); + } + return str; + } + /** *

Remove a newline if and only if it is at the end * of the supplied String.

@@ -857,6 +893,7 @@ public class StringUtils { * @param str String to chomp from * @return String without chomped ending * @throws NullPointerException if str is null + * @deprecated use chomp(String) instead */ public static String chompLast(String str) { return chompLast(str, "\n"); @@ -869,6 +906,7 @@ public class StringUtils { * @param sep String to chomp * @return String without chomped ending * @throws NullPointerException if str or sep is null + * @deprecated use chomp(String,String) instead */ public static String chompLast(String str, String sep) { if (str.length() == 0) { @@ -884,12 +922,14 @@ public class StringUtils { /** *

Remove everything and return the last value of a supplied String, and - * everything after it from a String.

+ * everything after it from a String. + * [That makes no sense. Just use sliceRemainder() :-)]

* * @param str String to chomp from * @param sep String to chomp * @return String chomped * @throws NullPointerException if str or sep is null + * @deprecated use sliceRemainder(String,String) instead */ public static String getChomp(String str, String sep) { int idx = str.lastIndexOf(sep); @@ -910,6 +950,7 @@ public class StringUtils { * @param sep String to chomp * @return String without chomped beginning * @throws NullPointerException if str or sep is null + * @deprecated use sliceFirstRemainder(String,String) instead */ public static String prechomp(String str, String sep) { int idx = str.indexOf(sep); @@ -928,6 +969,7 @@ public class StringUtils { * @param sep String to chomp * @return String prechomped * @throws NullPointerException if str or sep is null + * @deprecated use sliceFirst(String) instead */ public static String getPrechomp(String str, String sep) { int idx = str.indexOf(sep); @@ -976,6 +1018,7 @@ public class StringUtils { * @param str String to chop a newline from * @return String without newline * @throws NullPointerException if str is null + * @deprecated use chomp(String) instead */ public static String chopNewline(String str) { int lastIdx = str.length() - 1; @@ -991,6 +1034,102 @@ public class StringUtils { } + // Slicing + //-------------------------------------------------------------------------- + + /** + *

Remove the last newline, and everything after it from a String.

+ * (This method was formerly named chomp or chopNewline.) + * + * @param str String to slice the newline from + * @return String without sliced newline + * @throws NullPointerException if str is null + */ + public static String slice(String str) { + return slice(str, "\n"); + } + + /** + *

Find the last occurence of a separator String; + * remove it and everything after it.

+ * (This method was formerly named chomp.) + * + * @param str String to slice from + * @param sep String to slice + * @return String without sliced ending + * @throws NullPointerException if str or sep is null + */ + public static String slice(String str, String sep) { + int idx = str.lastIndexOf(sep); + if (idx != -1) { + return str.substring(0, idx); + } else { + return str; + } + } + + /** + *

Find the last occurence of a separator String, and return + * everything after it.

+ * (This method was formerly named getchomp. Also, now it does not + * include the separator in the return value.) + * + * @param str String to slice from + * @param sep String to slice + * @return String sliced + * @throws NullPointerException if str or sep is null + */ + public static String sliceRemainder(String str, String sep) { + int idx = str.lastIndexOf(sep); + if (idx == str.length() - sep.length()) { + return ""; + } else if (idx != -1) { + return str.substring(idx + sep.length()); + } else { + return ""; + } + } + + /** + *

Find the first occurence of a separator String, and return + * everything after it.

+ * (This method was formerly named prechomp. Also, previously + * it included the separator in the return value; now it does not.) + * + * @param str String to slice from + * @param sep String to slice + * @return String without sliced beginning + * @throws NullPointerException if str or sep is null + */ + public static String sliceFirstRemainder(String str, String sep) { + int idx = str.indexOf(sep); + if (idx != -1) { + return str.substring(idx + sep.length()); + } else { + return str; + } + } + + /** + *

Find the first occurence of a separator string; + * return everything before it (but not including the separator).

+ * (This method was formerly named getPrechomp. Also, it used to + * include the separator, but now it does not.) + * + * @param str String to slice from + * @param sep String to slice + * @return String presliced + * @throws NullPointerException if str or sep is null + */ + public static String sliceFirst(String str, String sep) { + int idx = str.indexOf(sep); + if (idx != -1) { + return str.substring(0, idx); + } else { + return ""; + } + } + // Conversion //-------------------------------------------------------------------------- diff --git a/src/test/org/apache/commons/lang/StringUtilsTest.java b/src/test/org/apache/commons/lang/StringUtilsTest.java index 3895bed42..01d482c9a 100644 --- a/src/test/org/apache/commons/lang/StringUtilsTest.java +++ b/src/test/org/apache/commons/lang/StringUtilsTest.java @@ -69,7 +69,7 @@ import junit.textui.TestRunner; * @author Henning P. Schmiedehausen - * @version $Id: StringUtilsTest.java,v 1.16 2003/03/23 21:51:19 scolebourne Exp $ + * @version $Id: StringUtilsTest.java,v 1.17 2003/03/29 16:17:21 alex Exp $ */ public class StringUtilsTest extends TestCase { @@ -153,7 +153,7 @@ public class StringUtilsTest extends TestCase { } public void testJoin() { - assertEquals("concatenate(Object[]) failed", + assertEquals("concatenate(Object[]) failed", TEXT_LIST_NOSEP, StringUtils.concatenate(ARRAY_LIST)); assertEquals("join(Object[], String) failed", TEXT_LIST, StringUtils.join(ARRAY_LIST, SEPARATOR)); @@ -173,7 +173,7 @@ public class StringUtilsTest extends TestCase { StringUtils.join(Arrays.asList(ARRAY_LIST).iterator(), null)); - assertEquals("concatenate(Object[]) failed", + assertEquals("concatenate(Object[]) failed", "", StringUtils.concatenate(EMPTY_ARRAY_LIST)); assertEquals("join(Object[], String) failed", "", StringUtils.join(EMPTY_ARRAY_LIST, SEPARATOR)); @@ -268,10 +268,7 @@ public class StringUtilsTest extends TestCase { " "+FOO+" ", StringUtils.center(FOO, 9) ); } - public void testChompFunctions() { - assertEquals("chomp(String) failed", - FOO, StringUtils.chomp(FOO + "\n" + FOO) ); - + public void testDeprecatedChompFunctions() { assertEquals("chompLast(String) failed", FOO, StringUtils.chompLast(FOO + "\n") ); @@ -284,13 +281,90 @@ public class StringUtilsTest extends TestCase { assertEquals("getPrechomp(String, String) failed", FOO + "\n", StringUtils.getPrechomp(FOO + "\n" + FOO, "\n") ); - assertEquals("chop(String, String) failed", - FOO, StringUtils.chop(FOO + "\r\n") ); - assertEquals("chopNewline(String, String) failed", FOO, StringUtils.chopNewline(FOO + "\r\n") ); } + public void testChop() { + + String[][] chopCases = { + { FOO + "\r\n", FOO } , + { FOO + "\n" , FOO } , + { FOO + "\r", FOO }, + { "foo", "fo"}, + { "foo\nfoo", "foo\nfo" }, + { "\n", "" }, + { "\r", "" }, + { "\r\n", "" }, + }; + for (int i = 0; i < chopCases.length; i++) { + String original = chopCases[i][0]; + String expectedResult = chopCases[i][1]; + assertEquals("chop(String) failed", + expectedResult, StringUtils.chop(original)); + } + } + + public void testChomp() { + + String[][] chompCases = { + { FOO + "\r\n", FOO } , + { FOO + "\n" , FOO } , + { FOO + "\r", FOO }, + { FOO, FOO }, + { FOO + "\n\n", FOO + "\n"}, + { "foo\nfoo", "foo\nfoo" }, + { "\n", "" }, + { "\r", "" }, + { "\r\n", "" }, + }; + for (int i = 0; i < chompCases.length; i++) { + String original = chompCases[i][0]; + String expectedResult = chompCases[i][1]; + assertEquals("chomp(String) failed", + expectedResult, StringUtils.chomp(original)); + } + + assertEquals("chomp(String, String) failed", + "foo", StringUtils.chomp("foobar", "bar")); + assertEquals("chomp(String, String) failed", + "foobar", StringUtils.chomp("foobar", "baz")); + assertEquals("chomp(String, String) failed", + "foo", StringUtils.chomp("foo", "foooo")); + } + + public void testSliceFunctions() { + + String[][] sliceCases = { + {"foo\n", "foo"}, + {"foo\nbar", "foo"}, + {"foo\nbar\n", "foo\nbar"}, + {"foo\nbar\nbaz", "foo\nbar"}, + }; + for (int i = 0; i < sliceCases.length; i++) { + String original = sliceCases[i][0]; + String expectedResult = sliceCases[i][1]; + assertEquals("slice(String) failed", + expectedResult, StringUtils.slice(original)); + } + + String original = "fooXXbarXXbaz"; + String sep = "XX"; + + assertEquals("slice(String,String) failed", + "fooXXbar", StringUtils.slice(original, sep) ); + + assertEquals("sliceRemainder(String, String) failed", + "baz", StringUtils.sliceRemainder(original, sep) ); + + assertEquals("sliceFirst(String, String) failed", + "foo", StringUtils.sliceFirst(original, sep) ); + + assertEquals("sliceFirstRemainder(String, String) failed", + "barXXbaz", StringUtils.sliceFirstRemainder(original, sep) ); + + } + public void testPadFunctions() { assertEquals("rightPad(String, int) failed", "1234 ", StringUtils.rightPad ("1234", 8) ); @@ -317,13 +391,13 @@ public class StringUtilsTest extends TestCase { assertEquals("reverse(empty-string) failed", "", StringUtils.reverse("") ); assertEquals("reverseDelimitedString(String,'.') failed", - "org.apache.test", + "org.apache.test", StringUtils.reverseDelimitedString("test.apache.org", ".") ); assertEquals("reverseDelimitedString(empty-string,'.') failed", - "", + "", StringUtils.reverseDelimitedString("", ".") ); assertEquals("reverseDelimitedString(String,' ') failed", - "once upon a time", + "once upon a time", StringUtils.reverseDelimitedString("time a upon once"," ") ); } @@ -359,13 +433,13 @@ public class StringUtilsTest extends TestCase { "\\u0234", StringUtils.escape("\u0234") ); assertEquals("escape(String) failed", "\\u00fd", StringUtils.escape("\u00fd") ); - assertEquals("unescape(String) failed", + assertEquals("unescape(String) failed", "", StringUtils.unescape("") ); - assertEquals("unescape(String) failed", + assertEquals("unescape(String) failed", "test", StringUtils.unescape("test") ); - assertEquals("unescape(String) failed", + assertEquals("unescape(String) failed", "\ntest\b", StringUtils.unescape("\\ntest\\b") ); - assertEquals("unescape(String) failed", + assertEquals("unescape(String) failed", "\u123425foo\ntest\b", StringUtils.unescape("\\u123425foo\\ntest\\b") ); }