commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pascalschumac...@apache.org
Subject [lang] LANG-1160: StringUtils#abbreviate should support 'custom ellipses' parameter (closes #195)
Date Fri, 28 Oct 2016 17:33:57 GMT
Repository: commons-lang
Updated Branches:
  refs/heads/master a40b2a907 -> c37a911d3


LANG-1160: StringUtils#abbreviate should support 'custom ellipses' parameter (closes #195)


Project: http://git-wip-us.apache.org/repos/asf/commons-lang/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-lang/commit/c37a911d
Tree: http://git-wip-us.apache.org/repos/asf/commons-lang/tree/c37a911d
Diff: http://git-wip-us.apache.org/repos/asf/commons-lang/diff/c37a911d

Branch: refs/heads/master
Commit: c37a911d3a1541adc25c8d76f717015b2266d123
Parents: a40b2a9
Author: Bruno P. Kinoshita <kinow@apache.org>
Authored: Thu Oct 13 22:55:17 2016 +1300
Committer: pascalschumacher <pascalschumacher@gmx.net>
Committed: Fri Oct 28 19:33:47 2016 +0200

----------------------------------------------------------------------
 src/changes/changes.xml                         |   1 +
 .../org/apache/commons/lang3/StringUtils.java   | 119 ++++++++++++++++---
 .../apache/commons/lang3/StringUtilsTest.java   | 101 ++++++++++++++--
 3 files changed, 196 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-lang/blob/c37a911d/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 437d59b..4b8f2b4 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -53,6 +53,7 @@ The <action> type attribute can be add,update,fix,remove.
     <action issue="LANG-1278" type="fix" dev="pschumacher" due-to="Duke Yin">BooleanUtils
javadoc issues</action>
     <action issue="LANG-1070" type="fix" dev="pschumacher" due-to="Paul Pogonyshev">ArrayUtils#add
confusing example in javadoc</action>
     <action issue="LANG-1271" type="fix" dev="pschumacher" due-to="Pierre Templier">StringUtils#isAnyEmpty
and #isAnyBlank should return false for an empty array</action>
+    <action issue="LANG-1160" type="add" dev="kinow">StringUtils#abbreviate should
support 'custom ellipses' parameter</action>
     <action issue="LANG-1270" type="add" dev="pschumacher" due-to="Pierre Templier">Add
StringUtils#isAnyNotEmpty and #isAnyNotBlank</action>
     <action issue="LANG-1277" type="update" dev="pschumacher" due-to="yufcuy">StringUtils#getLevenshteinDistance
reduce memory consumption</action>
     <action issue="LANG-1279" type="update" dev="ggregory">Update Java requirement
from Java 6 to 7.</action>

http://git-wip-us.apache.org/repos/asf/commons-lang/blob/c37a911d/src/main/java/org/apache/commons/lang3/StringUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/lang3/StringUtils.java b/src/main/java/org/apache/commons/lang3/StringUtils.java
index a6c7c56..dbd7ff4 100644
--- a/src/main/java/org/apache/commons/lang3/StringUtils.java
+++ b/src/main/java/org/apache/commons/lang3/StringUtils.java
@@ -79,7 +79,7 @@ import java.util.regex.Pattern;
  *  <li><b>Reverse/ReverseDelimited</b>
  *      - reverses a String</li>
  *  <li><b>Abbreviate</b>
- *      - abbreviates a string using ellipsis</li>
+ *      - abbreviates a string using ellipsis or another given String</li>
  *  <li><b>Difference</b>
  *      - compares Strings and reports on their differences</li>
  *  <li><b>LevenshteinDistance</b>
@@ -7377,7 +7377,8 @@ public class StringUtils {
      * @since 2.0
      */
     public static String abbreviate(final String str, final int maxWidth) {
-        return abbreviate(str, 0, maxWidth);
+        final String defaultAbbrevMarker = "...";
+        return abbreviate(str, defaultAbbrevMarker, 0, maxWidth);
     }
 
     /**
@@ -7416,11 +7417,98 @@ public class StringUtils {
      * @since 2.0
      */
     public static String abbreviate(final String str, int offset, final int maxWidth) {
-        if (str == null) {
-            return null;
+        final String defaultAbbrevMarker = "...";
+        return abbreviate(str, defaultAbbrevMarker, offset, maxWidth);
+    }
+
+    /**
+     * <p>Abbreviates a String using another given String as replacement marker. This
will turn
+     * "Now is the time for all good men" into "Now is the time for..." if "..." was defined
+     * as the replacement marker.</p>
+     *
+     * <p>Specifically:</p>
+     * <ul>
+     *   <li>If the number of characters in {@code str} is less than or equal to 
+     *       {@code maxWidth}, return {@code str}.</li>
+     *   <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length)
+ abbrevMarker)}.</li>
+     *   <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw
an
+     *       {@code IllegalArgumentException}.</li>
+     *   <li>In no case will it return a String of length greater than
+     *       {@code maxWidth}.</li>
+     * </ul>
+     *
+     * <pre>
+     * StringUtils.abbreviate(null, "...", *)      = null
+     * StringUtils.abbreviate("abcdefg", null, *)  = "abcdefg"
+     * StringUtils.abbreviate("", "...", 4)        = ""
+     * StringUtils.abbreviate("abcdefg", ".", 5)   = "abcd."
+     * StringUtils.abbreviate("abcdefg", ".", 7)   = "abcdefg"
+     * StringUtils.abbreviate("abcdefg", ".", 8)   = "abcdefg"
+     * StringUtils.abbreviate("abcdefg", "..", 4)  = "ab.."
+     * StringUtils.abbreviate("abcdefg", "..", 3)  = "a.."
+     * StringUtils.abbreviate("abcdefg", "..", 2)  = IllegalArgumentException
+     * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
+     * </pre>
+     *
+     * @param str  the String to check, may be null
+     * @param abbrevMarker  the String used as replacement marker
+     * @param maxWidth  maximum length of result String, must be at least {@code abbrevMarker.length
+ 1}
+     * @return abbreviated String, {@code null} if null String input
+     * @throws IllegalArgumentException if the width is too small
+     * @since 3.5
+     */
+    public static String abbreviate(final String str, final String abbrevMarker, final int
maxWidth) {
+        return abbreviate(str, abbrevMarker, 0, maxWidth);
+    }
+
+    /**
+     * <p>Abbreviates a String using a given replacement marker. This will turn
+     * "Now is the time for all good men" into "...is the time for..." if "..." was defined
+     * as the replacement marker.</p>
+     *
+     * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify
+     * a "left edge" offset.  Note that this left edge is not necessarily going to
+     * be the leftmost character in the result, or the first character following the
+     * replacement marker, but it will appear somewhere in the result.
+     *
+     * <p>In no case will it return a String of length greater than {@code maxWidth}.</p>
+     *
+     * <pre>
+     * StringUtils.abbreviate(null, null, *, *)                 = null
+     * StringUtils.abbreviate("abcdefghijklmno", null, *, *)    = "abcdefghijklmno"
+     * StringUtils.abbreviate("", "...", 0, 4)                  = ""
+     * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
+     * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10)    = "abcdefghi,"
+     * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10)    = "abcdefghi,"
+     * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10)    = "abcdefghi,"
+     * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10)   = "::efghij::"
+     * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10)  = "...ghij..."
+     * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10)    = "*ghijklmno"
+     * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10)   = "'ghijklmno"
+     * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10)   = "!ghijklmno"
+     * StringUtils.abbreviate("abcdefghij", "abra", 0, 4)       = IllegalArgumentException
+     * StringUtils.abbreviate("abcdefghij", "...", 5, 6)        = IllegalArgumentException
+     * </pre>
+     *
+     * @param str  the String to check, may be null
+     * @param abbrevMarker  the String used as replacement marker
+     * @param offset  left edge of source String
+     * @param maxWidth  maximum length of result String, must be at least 4
+     * @return abbreviated String, {@code null} if null String input
+     * @throws IllegalArgumentException if the width is too small
+     * @since 3.5
+     */
+    public static String abbreviate(final String str, final String abbrevMarker, int offset,
final int maxWidth) {
+        if (isEmpty(str) || isEmpty(abbrevMarker)) {
+            return str;
         }
-        if (maxWidth < 4) {
-            throw new IllegalArgumentException("Minimum abbreviation width is 4");
+
+        final int abbrevMarkerLength = abbrevMarker.length();
+        final int minAbbrevWidth = abbrevMarkerLength + 1;
+        final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
+
+        if (maxWidth < minAbbrevWidth) {
+            throw new IllegalArgumentException(String.format("Minimum abbreviation width
is %d", minAbbrevWidth));
         }
         if (str.length() <= maxWidth) {
             return str;
@@ -7428,20 +7516,19 @@ public class StringUtils {
         if (offset > str.length()) {
             offset = str.length();
         }
-        if (str.length() - offset < maxWidth - 3) {
-            offset = str.length() - (maxWidth - 3);
+        if (str.length() - offset < maxWidth - abbrevMarkerLength) {
+            offset = str.length() - (maxWidth - abbrevMarkerLength);
         }
-        final String abrevMarker = "...";
-        if (offset <= 4) {
-            return str.substring(0, maxWidth - 3) + abrevMarker;
+        if (offset <= abbrevMarkerLength+1) {
+            return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
         }
-        if (maxWidth < 7) {
-            throw new IllegalArgumentException("Minimum abbreviation width with offset is
7");
+        if (maxWidth < minAbbrevWidthOffset) {
+            throw new IllegalArgumentException(String.format("Minimum abbreviation width
with offset is %d", minAbbrevWidthOffset));
         }
-        if (offset + maxWidth - 3 < str.length()) {
-            return abrevMarker + abbreviate(str.substring(offset), maxWidth - 3);
+        if (offset + maxWidth - abbrevMarkerLength < str.length()) {
+            return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth
- abbrevMarkerLength);
         }
-        return abrevMarker + str.substring(str.length() - (maxWidth - 3));
+        return abbrevMarker + str.substring(str.length() - (maxWidth - abbrevMarkerLength));
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/commons-lang/blob/c37a911d/src/test/java/org/apache/commons/lang3/StringUtilsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/lang3/StringUtilsTest.java b/src/test/java/org/apache/commons/lang3/StringUtilsTest.java
index 524bd8d..e8b4f6e 100644
--- a/src/test/java/org/apache/commons/lang3/StringUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/StringUtilsTest.java
@@ -1934,9 +1934,36 @@ public class StringUtilsTest {
         assertEquals("", StringUtils.abbreviate("", 4));
 
         try {
+            StringUtils.abbreviate("abc", 3);
+            fail("StringUtils.abbreviate expecting IllegalArgumentException");
+        } catch (final IllegalArgumentException expected) {
+            // empty
+        }
+    }
+
+    @Test
+    public void testAbbreviate_StringStringInt() {
+        assertNull(StringUtils.abbreviate(null, null, 10));
+        assertNull(StringUtils.abbreviate(null, "...", 10));
+        assertEquals("paranaguacu", StringUtils.abbreviate("paranaguacu", null, 10));
+        assertEquals("", StringUtils.abbreviate("", "...", 2));
+        assertEquals("wai**", StringUtils.abbreviate("waiheke", "**", 5));
+        assertEquals("And af,,,,", StringUtils.abbreviate("And after a long time, he finally
met his son.", ",,,,", 10));
+
+        final String raspberry = "raspberry peach";
+        assertEquals("raspberry pe..", StringUtils.abbreviate(raspberry, "..", 14));
+        assertEquals("raspberry peach", StringUtils.abbreviate("raspberry peach", "---*---",
15));
+        assertEquals("raspberry peach", StringUtils.abbreviate("raspberry peach", ".", 16));
+        assertEquals("abc()(", StringUtils.abbreviate("abcdefg", "()(", 6));
+        assertEquals("abcdefg", StringUtils.abbreviate("abcdefg", ";", 7));
+        assertEquals("abcdefg", StringUtils.abbreviate("abcdefg", "_-", 8));
+        assertEquals("abc.", StringUtils.abbreviate("abcdefg", ".", 4));
+        assertEquals("", StringUtils.abbreviate("", 4));
+
+        try {
             @SuppressWarnings("unused")
             final
-            String res = StringUtils.abbreviate("abc", 3);
+            String res = StringUtils.abbreviate("abcdefghij", "...", 3);
             fail("StringUtils.abbreviate expecting IllegalArgumentException");
         } catch (final IllegalArgumentException ex) {
             // empty
@@ -1950,19 +1977,15 @@ public class StringUtilsTest {
         assertEquals("", StringUtils.abbreviate("", 2, 10));
 
         try {
-            @SuppressWarnings("unused")
-            final
-            String res = StringUtils.abbreviate("abcdefghij", 0, 3);
+            StringUtils.abbreviate("abcdefghij", 0, 3);
             fail("StringUtils.abbreviate expecting IllegalArgumentException");
-        } catch (final IllegalArgumentException ex) {
+        } catch (final IllegalArgumentException expected) {
             // empty
         }
         try {
-            @SuppressWarnings("unused")
-            final
-            String res = StringUtils.abbreviate("abcdefghij", 5, 6);
+            StringUtils.abbreviate("abcdefghij", 5, 6);
             fail("StringUtils.abbreviate expecting IllegalArgumentException");
-        } catch (final IllegalArgumentException ex) {
+        } catch (final IllegalArgumentException expected) {
             // empty
         }
 
@@ -2007,6 +2030,65 @@ public class StringUtilsTest {
     }
 
     @Test
+    public void testAbbreviate_StringStringIntInt() {
+        assertNull(StringUtils.abbreviate(null, null, 10, 12));
+        assertNull(StringUtils.abbreviate(null, "...", 10, 12));
+        assertEquals("", StringUtils.abbreviate("", null, 0, 10));
+        assertEquals("", StringUtils.abbreviate("", "...", 2, 10));
+
+        try {
+            StringUtils.abbreviate("abcdefghij", "::", 0, 2);
+            fail("StringUtils.abbreviate expecting IllegalArgumentException");
+        } catch (final IllegalArgumentException expected) {
+            // empty
+        }
+        try {
+            StringUtils.abbreviate("abcdefghij", "!!!", 5, 6);
+            fail("StringUtils.abbreviate expecting IllegalArgumentException");
+        } catch (final IllegalArgumentException expected) {
+            // empty
+        }
+
+        final String raspberry = "raspberry peach";
+        assertEquals("raspberry peach", StringUtils.abbreviate(raspberry, "--", 12, 15));
+
+        assertNull(StringUtils.abbreviate(null, ";", 7, 14));
+        assertAbbreviateWithAbbrevMarkerAndOffset("abcdefgh;;", ";;", -1, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("abcdefghi.", ".", 0, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("abcdefgh++", "++", 1, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("abcdefghi*", "*", 2, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("abcdef{{{{", "{{{{", 4, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("abcdef____", "____", 5, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("==fghijk==", "==", 5, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("___ghij___", "___", 6, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("/ghijklmno", "/", 7, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("/ghijklmno", "/", 8, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("/ghijklmno", "/", 9, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("///ijklmno", "///", 10, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("//hijklmno", "//", 10, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("//hijklmno", "//", 11, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("...ijklmno", "...", 12, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("/ghijklmno", "/", 13, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("/ghijklmno", "/", 14, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("999ijklmno", "999", 15, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("_ghijklmno", "_", 16, 10);
+        assertAbbreviateWithAbbrevMarkerAndOffset("+ghijklmno", "+", Integer.MAX_VALUE, 10);
+    }
+
+    private void assertAbbreviateWithAbbrevMarkerAndOffset(final String expected, final String
abbrevMarker, final int offset, final int maxWidth) {
+        final String abcdefghijklmno = "abcdefghijklmno";
+        final String message = "abbreviate(String,String,int,int) failed";
+        final String actual = StringUtils.abbreviate(abcdefghijklmno, abbrevMarker, offset,
maxWidth);
+        if (offset >= 0 && offset < abcdefghijklmno.length()) {
+            assertTrue(message + " -- should contain offset character",
+                    actual.indexOf((char) ('a' + offset)) != -1);
+        }
+        assertTrue(message + " -- should not be greater than maxWidth",
+                actual.length() <= maxWidth);
+        assertEquals(message, expected, actual);
+    }
+
+    @Test
     public void testAbbreviateMiddle() {
         // javadoc examples
         assertNull(StringUtils.abbreviateMiddle(null, null, 0));
@@ -2047,6 +2129,7 @@ public class StringUtilsTest {
         assertEquals("ab.ef", StringUtils.abbreviateMiddle("abcdef", ".", 5));
     }
 
+    //-----------------------------------------------------------------------
     @Test
     public void testTruncate_StringInt() {
         assertNull(StringUtils.truncate(null, 12));


Mime
View raw message