From d205225cefde08abe5ec5f2eaacc7e864f916d8b Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 15 Sep 2020 01:00:26 +0800 Subject: [PATCH] fix StrUtil bug --- CHANGELOG.md | 3 +- .../java/cn/hutool/core/text/StrBuilder.java | 3 + .../java/cn/hutool/core/util/StrUtil.java | 17 ++- .../java/cn/hutool/core/util/StrUtilTest.java | 121 ++++++++---------- .../java/cn/hutool/json/Issue1075Test.java | 19 ++- 5 files changed, 85 insertions(+), 78 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65d0583ab..3e9aed2ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -# 5.4.3 (2020-09-13) +# 5.4.3 (2020-09-15) ### 新特性 * 【core 】 使用静态的of方法来new对象(pr#177@Gitee) @@ -16,6 +16,7 @@ ### Bug修复 * 【core 】 修复Dict.of错误(issue#I1UUO5@Gitee) * 【core 】 修复UrlBuilder地址参数问题(issue#I1UWCA@Gitee) +* 【core 】 修复StrUtil.toSymbolCase转换问题(issue#1075@Github) ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/text/StrBuilder.java b/hutool-core/src/main/java/cn/hutool/core/text/StrBuilder.java index 12267f3f3..91535be4f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/StrBuilder.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/StrBuilder.java @@ -462,6 +462,9 @@ public class StrBuilder implements CharSequence, Appendable, Serializable { @Override public char charAt(int index) { + if(index < 0){ + index = this.position + index; + } if ((index < 0) || (index > this.position)) { throw new StringIndexOutOfBoundsException(index); } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java index 867b54d42..28ff651d7 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java @@ -2633,7 +2633,7 @@ public class StrUtil { } final int length = str.length(); - final StringBuilder sb = new StringBuilder(); + final StrBuilder sb = new StrBuilder(); char c; for (int i = 0; i < length; i++) { c = str.charAt(i); @@ -2642,12 +2642,12 @@ public class StrUtil { // 遇到大写字母处理 final Character nextChar = (i < str.length() - 1) ? str.charAt(i + 1) : null; if (null != preChar && Character.isUpperCase(preChar)) { - // 前一个字符为大写,则按照一个词对待 + // 前一个字符为大写,则按照一个词对待,例如AB sb.append(c); - } else if (null != nextChar && Character.isUpperCase(nextChar)) { - // 后一个为大写字母,按照一个词对待 + } else if (null != nextChar && (false == Character.isLowerCase(nextChar))) { + // 后一个为非小写字母,按照一个词对待 if (null != preChar && symbol != preChar) { - // 前一个是非大写时按照新词对待,加连接符 + // 前一个是非大写时按照新词对待,加连接符,例如xAB sb.append(symbol); } sb.append(c); @@ -2660,8 +2660,11 @@ public class StrUtil { sb.append(Character.toLowerCase(c)); } } else { - if (sb.length() > 0 && Character.isUpperCase(sb.charAt(sb.length() - 1)) && symbol != c) { - // 当结果中前一个字母为大写,当前为小写,说明此字符为新词开始(连接符也表示新词) + if (symbol != c + && sb.length() > 0 + && Character.isUpperCase(sb.charAt(-1)) + && Character.isLowerCase(c)) { + // 当结果中前一个字母为大写,当前为小写(非数字或字符),说明此字符为新词开始(连接符也表示新词) sb.append(symbol); } // 小写或符号 diff --git a/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java index a022b28ab..c66ce1dbe 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/StrUtilTest.java @@ -8,9 +8,8 @@ import java.util.List; /** * 字符串工具类单元测试 - * - * @author Looly * + * @author Looly */ public class StrUtilTest { @@ -19,14 +18,14 @@ public class StrUtilTest { String blank = "   "; Assert.assertTrue(StrUtil.isBlank(blank)); } - + @Test public void trimTest() { String blank = " 哈哈  "; String trim = StrUtil.trim(blank); Assert.assertEquals("哈哈", trim); } - + @Test public void cleanBlankTest() { // 包含:制表符、英文空格、不间断空白符、全角空格 @@ -39,7 +38,7 @@ public class StrUtilTest { public void cutTest() { String str = "aaabbbcccdddaadfdfsdfsdf0"; String[] cut = StrUtil.cut(str, 4); - Assert.assertArrayEquals(new String[] { "aaab", "bbcc", "cddd", "aadf", "dfsd", "fsdf", "0" }, cut); + Assert.assertArrayEquals(new String[]{"aaab", "bbcc", "cddd", "aadf", "dfsd", "fsdf", "0"}, cut); } @Test @@ -59,20 +58,20 @@ public class StrUtilTest { public void splitToLongTest() { String str = "1,2,3,4, 5"; long[] longArray = StrUtil.splitToLong(str, ','); - Assert.assertArrayEquals(new long[] { 1, 2, 3, 4, 5 }, longArray); + Assert.assertArrayEquals(new long[]{1, 2, 3, 4, 5}, longArray); longArray = StrUtil.splitToLong(str, ","); - Assert.assertArrayEquals(new long[] { 1, 2, 3, 4, 5 }, longArray); + Assert.assertArrayEquals(new long[]{1, 2, 3, 4, 5}, longArray); } @Test public void splitToIntTest() { String str = "1,2,3,4, 5"; int[] intArray = StrUtil.splitToInt(str, ','); - Assert.assertArrayEquals(new int[] { 1, 2, 3, 4, 5 }, intArray); + Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, intArray); intArray = StrUtil.splitToInt(str, ","); - Assert.assertArrayEquals(new int[] { 1, 2, 3, 4, 5 }, intArray); + Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, intArray); } @Test @@ -80,7 +79,7 @@ public class StrUtilTest { String template = "你好,我是{name},我的电话是:{phone}"; String result = StrUtil.format(template, Dict.create().set("name", "张三").set("phone", "13888881111")); Assert.assertEquals("你好,我是张三,我的电话是:13888881111", result); - + String result2 = StrUtil.format(template, Dict.create().set("name", "张三").set("phone", null)); Assert.assertEquals("你好,我是张三,我的电话是:{phone}", result2); } @@ -102,11 +101,11 @@ public class StrUtilTest { str = "abcd123"; strip = StrUtil.strip(str, null, "567"); Assert.assertEquals("abcd123", strip); - - Assert.assertEquals("", StrUtil.strip("a","a")); - Assert.assertEquals("", StrUtil.strip("a","a", "b")); + + Assert.assertEquals("", StrUtil.strip("a", "a")); + Assert.assertEquals("", StrUtil.strip("a", "a", "b")); } - + @Test public void stripIgnoreCaseTest() { String str = "abcd123"; @@ -144,7 +143,7 @@ public class StrUtilTest { Assert.assertEquals(2, StrUtil.indexOfIgnoreCase("aabaabaa", "", 2)); Assert.assertEquals(-1, StrUtil.indexOfIgnoreCase("abc", "", 9)); } - + @Test public void lastIndexOfTest() { String a = "aabbccddcc"; @@ -180,17 +179,17 @@ public class StrUtilTest { String result = StrUtil.replace("123", "2", "3"); Assert.assertEquals("133", result); } - + @Test public void replaceTest3() { String result = StrUtil.replace(",abcdef,", ",", "|"); Assert.assertEquals("|abcdef|", result); } - + @Test public void replaceTest4() { String a = "1039"; - String result = StrUtil.padPre(a,8,"0"); //在字符串1039前补4个0 + String result = StrUtil.padPre(a, 8, "0"); //在字符串1039前补4个0 Assert.assertEquals("00001039", result); } @@ -228,7 +227,7 @@ public class StrUtilTest { String rightAnswer = StrUtil.subByCodePoint(test, 0, 3); Assert.assertEquals("\uD83E\uDD14\uD83D\uDC4D\uD83C\uDF53", rightAnswer); } - + @Test public void subBeforeTest() { String a = "abcderghigh"; @@ -238,14 +237,14 @@ public class StrUtilTest { Assert.assertEquals("abc", pre); pre = StrUtil.subBefore(a, 'a', false); Assert.assertEquals("", pre); - + //找不到返回原串 pre = StrUtil.subBefore(a, 'k', false); Assert.assertEquals(a, pre); pre = StrUtil.subBefore(a, 'k', true); Assert.assertEquals(a, pre); } - + @Test public void subAfterTest() { String a = "abcderghigh"; @@ -255,7 +254,7 @@ public class StrUtilTest { Assert.assertEquals("erghigh", pre); pre = StrUtil.subAfter(a, 'h', true); Assert.assertEquals("", pre); - + //找不到字符返回空串 pre = StrUtil.subAfter(a, 'k', false); Assert.assertEquals("", pre); @@ -306,20 +305,20 @@ public class StrUtilTest { result = StrUtil.move(str, 7, 12, 0); Assert.assertEquals("aaaaaaa22222bbbbbbb", result); } - + @Test public void removePrefixIgnorecaseTest() { String a = "aaabbb"; String prefix = "aaa"; Assert.assertEquals("bbb", StrUtil.removePrefixIgnoreCase(a, prefix)); - + prefix = "AAA"; Assert.assertEquals("bbb", StrUtil.removePrefixIgnoreCase(a, prefix)); - + prefix = "AAABBB"; Assert.assertEquals("", StrUtil.removePrefixIgnoreCase(a, prefix)); } - + @Test public void maxLengthTest() { String text = "我是一段正文,很长的正文,需要截取的正文"; @@ -330,13 +329,13 @@ public class StrUtilTest { str = StrUtil.maxLength(text, 50); Assert.assertEquals(text, str); } - + @Test public void toCamelCaseTest() { String str = "Table_Test_Of_day"; String result = StrUtil.toCamelCase(str); Assert.assertEquals("tableTestOfDay", result); - + String str1 = "TableTestOfDay"; String result1 = StrUtil.toCamelCase(str1); Assert.assertEquals("TableTestOfDay", result1); @@ -344,30 +343,20 @@ public class StrUtilTest { String abc1d = StrUtil.toCamelCase("abc_1d"); Assert.assertEquals("abc1d", abc1d); } - + @Test public void toUnderLineCaseTest() { - String str = "Table_Test_Of_day"; - String result = StrUtil.toUnderlineCase(str); - Assert.assertEquals("table_test_of_day", result); - - String str1 = "_Table_Test_Of_day_"; - String result1 = StrUtil.toUnderlineCase(str1); - Assert.assertEquals("_table_test_of_day_", result1); - - String str2 = "_Table_Test_Of_DAY_"; - String result2 = StrUtil.toUnderlineCase(str2); - Assert.assertEquals("_table_test_of_DAY_", result2); - - String str3 = "_TableTestOfDAYtoday"; - String result3 = StrUtil.toUnderlineCase(str3); - Assert.assertEquals("_table_test_of_DAY_today", result3); - - String str4 = "HelloWorld_test"; - String result4 = StrUtil.toUnderlineCase(str4); - Assert.assertEquals("hello_world_test", result4); + Dict.create() + .set("Table_Test_Of_day", "table_test_of_day") + .set("_Table_Test_Of_day_", "_table_test_of_day_") + .set("_Table_Test_Of_DAY_", "_table_test_of_DAY_") + .set("_TableTestOfDAYtoday", "_table_test_of_DAY_today") + .set("HelloWorld_test", "hello_world_test") + .set("H2", "H2") + .set("H#case", "H#case") + .forEach((key, value) -> Assert.assertEquals(value, StrUtil.toUnderlineCase(key))); } - + @Test public void containsAnyTest() { //字符 @@ -377,7 +366,7 @@ public class StrUtilTest { Assert.assertFalse(containsAny); containsAny = StrUtil.containsAny("aaabbbccc", 'd', 'c'); Assert.assertTrue(containsAny); - + //字符串 containsAny = StrUtil.containsAny("aaabbbccc", "a", "d"); Assert.assertTrue(containsAny); @@ -386,7 +375,7 @@ public class StrUtilTest { containsAny = StrUtil.containsAny("aaabbbccc", "d", "c"); Assert.assertTrue(containsAny); } - + @Test public void centerTest() { Assert.assertNull(StrUtil.center(null, 10)); @@ -396,24 +385,24 @@ public class StrUtilTest { Assert.assertEquals("abcd", StrUtil.center("abcd", 2)); Assert.assertEquals(" a ", StrUtil.center("a", 4)); } - + @Test public void padPreTest() { Assert.assertNull(StrUtil.padPre(null, 10, ' ')); Assert.assertEquals("001", StrUtil.padPre("1", 3, '0')); Assert.assertEquals("12", StrUtil.padPre("123", 2, '0')); - + Assert.assertNull(StrUtil.padPre(null, 10, "AA")); Assert.assertEquals("AB1", StrUtil.padPre("1", 3, "ABC")); Assert.assertEquals("12", StrUtil.padPre("123", 2, "ABC")); } - + @Test public void padAfterTest() { Assert.assertNull(StrUtil.padAfter(null, 10, ' ')); Assert.assertEquals("100", StrUtil.padAfter("1", 3, '0')); Assert.assertEquals("23", StrUtil.padAfter("123", 2, '0')); - + Assert.assertNull(StrUtil.padAfter(null, 10, "ABC")); Assert.assertEquals("1AB", StrUtil.padAfter("1", 3, "ABC")); Assert.assertEquals("23", StrUtil.padAfter("123", 2, "ABC")); @@ -421,13 +410,13 @@ public class StrUtilTest { @Test public void subBetweenAllTest() { - Assert.assertArrayEquals(new String[]{"yz","abc"},StrUtil.subBetweenAll("saho[yz]fdsadp[abc]a","[","]")); - Assert.assertArrayEquals(new String[]{"abc"}, StrUtil.subBetweenAll("saho[yzfdsadp[abc]a]","[","]")); - Assert.assertArrayEquals(new String[]{"abc", "abc"}, StrUtil.subBetweenAll("yabczyabcz","y","z")); - Assert.assertArrayEquals(new String[0], StrUtil.subBetweenAll(null,"y","z")); - Assert.assertArrayEquals(new String[0], StrUtil.subBetweenAll("","y","z")); - Assert.assertArrayEquals(new String[0], StrUtil.subBetweenAll("abc",null,"z")); - Assert.assertArrayEquals(new String[0], StrUtil.subBetweenAll("abc","y",null)); + Assert.assertArrayEquals(new String[]{"yz", "abc"}, StrUtil.subBetweenAll("saho[yz]fdsadp[abc]a", "[", "]")); + Assert.assertArrayEquals(new String[]{"abc"}, StrUtil.subBetweenAll("saho[yzfdsadp[abc]a]", "[", "]")); + Assert.assertArrayEquals(new String[]{"abc", "abc"}, StrUtil.subBetweenAll("yabczyabcz", "y", "z")); + Assert.assertArrayEquals(new String[0], StrUtil.subBetweenAll(null, "y", "z")); + Assert.assertArrayEquals(new String[0], StrUtil.subBetweenAll("", "y", "z")); + Assert.assertArrayEquals(new String[0], StrUtil.subBetweenAll("abc", null, "z")); + Assert.assertArrayEquals(new String[0], StrUtil.subBetweenAll("abc", "y", null)); } @Test @@ -436,15 +425,15 @@ public class StrUtilTest { String src1 = "/* \n* hutool */ asdas /* \n* hutool */"; String src2 = "/ * hutool */ asdas / * hutool */"; - String[] results1 = StrUtil.subBetweenAll(src1,"/**","*/"); + String[] results1 = StrUtil.subBetweenAll(src1, "/**", "*/"); Assert.assertEquals(0, results1.length); - String[] results2 = StrUtil.subBetweenAll(src2,"/*","*/"); + String[] results2 = StrUtil.subBetweenAll(src2, "/*", "*/"); Assert.assertEquals(0, results2.length); } @Test - public void briefTest(){ + public void briefTest() { String str = RandomUtil.randomString(1000); int maxLength = RandomUtil.randomInt(1000); String brief = StrUtil.brief(str, maxLength); @@ -460,7 +449,7 @@ public class StrUtilTest { } @Test - public void wrapAllTest(){ + public void wrapAllTest() { String[] strings = StrUtil.wrapAll("`", "`", StrUtil.splitToArray("1,2,3,4", ',')); Assert.assertEquals("[`1`, `2`, `3`, `4`]", StrUtil.utf8Str(strings)); diff --git a/hutool-json/src/test/java/cn/hutool/json/Issue1075Test.java b/hutool-json/src/test/java/cn/hutool/json/Issue1075Test.java index 0df5d2915..8eb8f718a 100644 --- a/hutool-json/src/test/java/cn/hutool/json/Issue1075Test.java +++ b/hutool-json/src/test/java/cn/hutool/json/Issue1075Test.java @@ -5,12 +5,23 @@ import org.junit.Assert; import org.junit.Test; public class Issue1075Test { - @Test - public void test() { - String s = "{\"f1\":\"f1\",\"F2\":\"f2\",\"fac\":\"fac\"}"; - ObjA o2 = JSONUtil.parseObj(s, JSONConfig.create().setIgnoreCase(true)).toBean(ObjA.class); + final String jsonStr = "{\"f1\":\"f1\",\"f2\":\"f2\",\"fac\":\"fac\"}"; + + @Test + public void testToBean() { + // 在不忽略大小写的情况下,f2、fac都不匹配 + ObjA o2 = JSONUtil.toBean(jsonStr, ObjA.class); + Assert.assertNull(o2.getFAC()); + Assert.assertNull(o2.getF2()); + } + + @Test + public void testToBeanIgnoreCase() { + // 在忽略大小写的情况下,f2、fac都匹配 + ObjA o2 = JSONUtil.parseObj(jsonStr, JSONConfig.create().setIgnoreCase(true)).toBean(ObjA.class); Assert.assertEquals("fac", o2.getFAC()); + Assert.assertEquals("f2", o2.getF2()); } @Data