diff --git a/OneBot-Interface/Core/Util/StringUtils.cs b/OneBot-Interface/Core/Util/StringUtils.cs index f0da5e7..c2a6612 100644 --- a/OneBot-Interface/Core/Util/StringUtils.cs +++ b/OneBot-Interface/Core/Util/StringUtils.cs @@ -16,16 +16,34 @@ public enum CamelCaseType { Upper, - Lower + Lower, + + None, } public enum CaseType { Lower, - Upper + Upper, + + None, } + private static CaseType EvaluateCaseType(char c) + { + if (char.IsUpper(c)) + { + return CaseType.Upper; + } + + if (char.IsLower(c)) + { + return CaseType.Lower; + } + + return CaseType.None; + } public static bool IsNullOrEmpty(string? value) => string.IsNullOrEmpty(value); @@ -80,9 +98,17 @@ public static string ToCamelCase(string s, CamelCaseType caseType, string[]? loc char[] result = new char[src.Length - ulCnt]; bool fstWord = true, fstLetter = true; string tmp = ""; + var lastCase = CaseType.None; + for (int i = 0, j = 0; i <= src.Length; i++) { - if (i == src.Length || src[i] == Underline || src[i] == Dash || char.IsSeparator(src[i])) + var cntCase = i < src.Length ? EvaluateCaseType(src[i]) : CaseType.None; + + if (i == src.Length || + src[i] == Underline || src[i] == Dash || + char.IsSeparator(src[i]) || + (i > 0 && lastCase != cntCase && cntCase == CaseType.Upper) + ) { if (lockedWords != null && lockedWords.Contains(tmp)) { @@ -95,6 +121,7 @@ public static string ToCamelCase(string s, CamelCaseType caseType, string[]? loc result[j - tmp.Length + k] = char.ToLower(result[j - tmp.Length + k]); } } + if (i < src.Length) { if (src[i] == Underline || src[i] == Dash) @@ -102,6 +129,13 @@ public static string ToCamelCase(string s, CamelCaseType caseType, string[]? loc fstLetter = true; tmp = ""; } + else if (i > 0 && lastCase != cntCase && cntCase == CaseType.Upper) + { + fstLetter = false; + result[j] = char.ToUpper(src[i]); + tmp = "" + char.ToUpper(src[i]); + j++; + } else { fstWord = true; @@ -126,11 +160,19 @@ public static string ToCamelCase(string s, CamelCaseType caseType, string[]? loc } else { + if (j != 1 && lastCase == CaseType.Upper && cntCase == CaseType.Lower) + { + result[j - 1] = char.ToUpper(result[j - 1]); + } + result[j] = char.ToLower(src[i]); } + tmp += char.ToUpper(src[i]); j++; } + + lastCase = cntCase; } return new string(result); @@ -164,20 +206,33 @@ public static string ToUpperSnakeCase(string s, string[]? lockedWords = null) /// public static string ToSeparatedCase(string s, char separator, CaseType caseType, string[]? lockedWords = null) { - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(16); char[] src = s.ToCharArray(); - bool fstWord = true; - for (int i = 0; i < src.Length; i++) + int t = 0; + var separated = false; + var lastCase = CaseType.None; + + for (int i = 0; i < src.Length; i++, t++) { + var cntCase = i < src.Length ? EvaluateCaseType(src[i]) : CaseType.None; + if (char.IsSeparator(src[i])) { sb.Append(src[i]); - fstWord = true; + t = -1; continue; } - if (char.IsUpper(src[i])) + + if (src[i] == Dash || src[i] == Underline) { + separated = true; + continue; + } + + if (separated || (lastCase != cntCase && cntCase == CaseType.Upper)) + { + separated = false; if (lockedWords != null) { bool skip = false; @@ -192,12 +247,11 @@ public static string ToSeparatedCase(string s, char separator, CaseType caseType break; } } + if (match) { - if (!fstWord) + if (t != 0) sb.Append(separator); - else - fstWord = false; for (int k = 0; k < word.Length; k++) { if (caseType == CaseType.Upper) @@ -206,23 +260,31 @@ public static string ToSeparatedCase(string s, char separator, CaseType caseType sb.Append(char.ToLower(src[i])); i++; } + i--; skip = true; break; } } + if (skip) continue; } - if (!fstWord) + + if (t != 0) sb.Append(separator); - else - fstWord = false; } + if (caseType == CaseType.Upper) + { sb.Append(char.ToUpper(src[i])); + } else + { sb.Append(char.ToLower(src[i])); + } + + lastCase = cntCase; } return sb.ToString(); diff --git a/OneBot-UnitTest/UnitTest/Util/StringUtilsTest.cs b/OneBot-UnitTest/UnitTest/Util/StringUtilsTest.cs index 1c56196..31bc72f 100644 --- a/OneBot-UnitTest/UnitTest/Util/StringUtilsTest.cs +++ b/OneBot-UnitTest/UnitTest/Util/StringUtilsTest.cs @@ -21,39 +21,75 @@ public void ToSnakeCaseTest() Assert.AreEqual("qq", lowerSnake.Convert("QQ")); Assert.AreEqual("id", lowerSnake.Convert("ID")); Assert.AreEqual("qq id", lowerSnake.Convert("QQ ID")); - - Assert.AreEqual("qq_qq_id qq_id_id_qq", StringUtils.ToSnakeCase("QQQQID QQIDIDQQ", StringUtils.CaseType.Lower, lockedWords)); - Assert.AreEqual("user_qq_token", StringUtils.ToSnakeCase("UserQQToken", StringUtils.CaseType.Lower, lockedWords)); - Assert.AreEqual("sweet_icelolly_id", StringUtils.ToSnakeCase("SweetIcelollyID", StringUtils.CaseType.Lower, lockedWords)); + + // ambiguous case + // Assert.AreEqual("qq_qq_id qq_id_id_qq", StringUtils.ToSnakeCase("QQQQID QQIDIDQQ", StringUtils.CaseType.Lower, lockedWords)); + + Assert.AreEqual("user_qq_token", + StringUtils.ToSnakeCase("UserQQToken", StringUtils.CaseType.Lower, lockedWords)); + Assert.AreEqual("sweet_icelolly_id", + StringUtils.ToSnakeCase("SweetIcelollyID", StringUtils.CaseType.Lower, lockedWords)); Assert.AreEqual("wey_sun+ice_eric_vancheng_dresses", - StringUtils.ToSnakeCase("WeySun+IceEricVanChengDresses", StringUtils.CaseType.Lower, new[] { "SUN+ICE", "VANCHENG" })); + StringUtils.ToSnakeCase("WeySun+IceEricVanChengDresses", StringUtils.CaseType.Lower, + new[] { "SUN+ICE", "VANCHENG" })); Assert.AreEqual("QQ", StringUtils.ToSnakeCase("QQ", StringUtils.CaseType.Upper, lockedWords)); Assert.AreEqual("ID", StringUtils.ToSnakeCase("ID", StringUtils.CaseType.Upper, lockedWords)); Assert.AreEqual("QQ ID", StringUtils.ToSnakeCase("QQ ID", StringUtils.CaseType.Upper, lockedWords)); - Assert.AreEqual("QQ_QQ_ID QQ_ID_ID_QQ", StringUtils.ToSnakeCase("QQQQID QQIDIDQQ", StringUtils.CaseType.Upper, lockedWords)); - Assert.AreEqual("USER_QQ_TOKEN", StringUtils.ToSnakeCase("UserQQToken", StringUtils.CaseType.Upper, lockedWords)); - Assert.AreEqual("SWEET_ICELOLLY_ID", StringUtils.ToSnakeCase("SweetIcelollyID", StringUtils.CaseType.Upper, lockedWords)); + Assert.AreEqual("QQ_QQ_ID QQ_ID_ID_QQ", + StringUtils.ToSnakeCase("QQQQID QQIDIDQQ", StringUtils.CaseType.Upper, lockedWords)); + Assert.AreEqual("USER_QQ_TOKEN", + StringUtils.ToSnakeCase("UserQQToken", StringUtils.CaseType.Upper, lockedWords)); + Assert.AreEqual("SWEET_ICELOLLY_ID", + StringUtils.ToSnakeCase("SweetIcelollyID", StringUtils.CaseType.Upper, lockedWords)); Assert.AreEqual("WEY_SUN+ICE_ERIC_VANCHENG_DRESSES", - StringUtils.ToSnakeCase("WeySun+IceEricVanChengDresses", StringUtils.CaseType.Upper, new[] { "SUN+ICE", "VANCHENG" })); + StringUtils.ToSnakeCase("WeySun+IceEricVanChengDresses", StringUtils.CaseType.Upper, + new[] { "SUN+ICE", "VANCHENG" })); + + Assert.AreEqual("one_another", StringUtils.ToSnakeCase("oneAnother", StringUtils.CaseType.Lower, lockedWords)); + Assert.AreEqual("ONE_ANOTHER", StringUtils.ToSnakeCase("oneAnother", StringUtils.CaseType.Upper, lockedWords)); + + Assert.AreEqual("ONE_ANOTHER", StringUtils.ToSnakeCase("one-Another", StringUtils.CaseType.Upper, lockedWords)); + Assert.AreEqual("ONE_ANOTHER", StringUtils.ToSnakeCase("one_Another", StringUtils.CaseType.Upper, lockedWords)); + Assert.AreEqual("ONE_ANOTHER", + StringUtils.ToSnakeCase("one_-Another", StringUtils.CaseType.Upper, lockedWords)); + Assert.AreEqual("ONE_ANOTHER", StringUtils.ToSnakeCase("ONE_ANOTHER", StringUtils.CaseType.Upper, lockedWords)); } - + [TestMethod] public void ToLowerCamelTest() { + Assert.AreEqual("userQQ", StringUtils.ToCamelCase("USER_QQ", StringUtils.CamelCaseType.Lower, lockedWords)); + Assert.AreEqual("userQQ", StringUtils.ToCamelCase("user_qq", StringUtils.CamelCaseType.Lower, lockedWords)); + Assert.AreEqual("userQQ", StringUtils.ToCamelCase("userQQ", StringUtils.CamelCaseType.Lower, lockedWords)); + Assert.AreEqual("userQQ", StringUtils.ToCamelCase("USER_QQ", StringUtils.CamelCaseType.Lower, lockedWords)); + Assert.AreEqual("userQQ", StringUtils.ToCamelCase("userQq", StringUtils.CamelCaseType.Lower, lockedWords)); Assert.AreEqual("userID", StringUtils.ToCamelCase("user_id", StringUtils.CamelCaseType.Lower, lockedWords)); Assert.AreEqual("qqID", StringUtils.ToCamelCase("qq_id", StringUtils.CamelCaseType.Lower, lockedWords)); Assert.AreEqual("icelolly", StringUtils.ToCamelCase("icelolly", StringUtils.CamelCaseType.Lower)); Assert.AreEqual("icelolly", StringUtils.ToCamelCase("Icelolly", StringUtils.CamelCaseType.Lower)); - Assert.AreEqual("icelolly", StringUtils.ToCamelCase("IceLOlly", StringUtils.CamelCaseType.Lower)); + + // ambiguous case + Assert.AreEqual("iceLOlly", StringUtils.ToCamelCase("IceLOlly", StringUtils.CamelCaseType.Lower)); + Assert.AreEqual("icelollyDress", StringUtils.ToCamelCase("icelolly_dress", StringUtils.CamelCaseType.Lower)); Assert.AreEqual("icelollyDress2", StringUtils.ToCamelCase("icelolly_dress2", StringUtils.CamelCaseType.Lower)); - Assert.AreEqual("icelollyDress", StringUtils.ToCamelCase("ICelolly_DRess", StringUtils.CamelCaseType.Lower)); - Assert.AreEqual("icelollyDress daiSuki", StringUtils.ToCamelCase("iCelolly_dRess dai_suki", StringUtils.CamelCaseType.Lower)); - Assert.AreEqual("icelollyDress daiSuki404", StringUtils.ToCamelCase("iCelolly_dRess dai_suki_404", StringUtils.CamelCaseType.Lower)); + Assert.AreEqual("icelollyDress2", StringUtils.ToCamelCase("icelolly_dress_2", StringUtils.CamelCaseType.Lower)); + + Assert.AreEqual("aDRess", StringUtils.ToCamelCase("A_DRess", StringUtils.CamelCaseType.Lower)); + + // ambiguous case + Assert.AreEqual("iCelollyDRess", StringUtils.ToCamelCase("ICelolly_DRess", StringUtils.CamelCaseType.Lower)); + + Assert.AreEqual("iCelollyDRess daiSuki", + StringUtils.ToCamelCase("iCelolly_dRess dai_suki", StringUtils.CamelCaseType.Lower)); + Assert.AreEqual("iCelollyDRess daiSuki404", + StringUtils.ToCamelCase("iCelolly_dRess dai_suki_404", StringUtils.CamelCaseType.Lower)); + Assert.AreEqual("iCelollyDRess", + StringUtils.ToCamelCase("iCelolly_----dRess", StringUtils.CamelCaseType.Lower)); } - + [TestMethod] public void ToUpperCamelTest() { @@ -62,11 +98,13 @@ public void ToUpperCamelTest() Assert.AreEqual("QQID", StringUtils.ToCamelCase("qq_id", StringUtils.CamelCaseType.Upper, lockedWords)); Assert.AreEqual("Icelolly", StringUtils.ToCamelCase("icelolly", StringUtils.CamelCaseType.Upper)); Assert.AreEqual("Icelolly", StringUtils.ToCamelCase("Icelolly", StringUtils.CamelCaseType.Upper)); - Assert.AreEqual("Icelolly", StringUtils.ToCamelCase("IceLOlly", StringUtils.CamelCaseType.Upper)); + Assert.AreEqual("IceLOlly", StringUtils.ToCamelCase("IceLOlly", StringUtils.CamelCaseType.Upper)); Assert.AreEqual("IcelollyDress", StringUtils.ToCamelCase("icelolly_dress", StringUtils.CamelCaseType.Upper)); Assert.AreEqual("IcelollyDress2", StringUtils.ToCamelCase("icelolly_dress2", StringUtils.CamelCaseType.Upper)); - Assert.AreEqual("IcelollyDress", StringUtils.ToCamelCase("ICelolly_DRess", StringUtils.CamelCaseType.Upper)); - Assert.AreEqual("IcelollyDress DaiSuki", StringUtils.ToCamelCase("iCelolly_dRess dai_suki", StringUtils.CamelCaseType.Upper)); - Assert.AreEqual("IcelollyDress DaiSuki404", StringUtils.ToCamelCase("iCelolly_dRess dai_suki_404", StringUtils.CamelCaseType.Upper)); + Assert.AreEqual("ICelollyDRess", StringUtils.ToCamelCase("ICelolly_DRess", StringUtils.CamelCaseType.Upper)); + Assert.AreEqual("ICelollyDRess DaiSuki", + StringUtils.ToCamelCase("iCelolly_dRess dai_suki", StringUtils.CamelCaseType.Upper)); + Assert.AreEqual("ICelollyDRess DaiSuki404", + StringUtils.ToCamelCase("iCelolly_dRess dai_suki_404", StringUtils.CamelCaseType.Upper)); } }