在将CamelCase转换为带空格的字符串时忽略现有空格
本文关键字:空格 字符串 CamelCase 转换 在将 | 更新日期: 2023-09-27 17:53:41
我想将camelCase
或PascalCase
单词拆分为单独的单词集合。
到目前为止,我已经:
Regex.Replace(value, @"('B[A-Z]+?(?=[A-Z][^A-Z])|'B[A-Z]+?(?=[^A-Z]))", " $0", RegexOptions.Compiled);
它可以很好地将"TestWord"转换为"Test Word",并保持单个单词不变,例如Testing
保持为Testing
。
然而,当我更喜欢ABC Test
时,ABCTest
被转换为A B C Test
。
尝试:
[A-Z][a-z]+|[A-Z]+(?=[A-Z][a-z])|[a-z]+|[A-Z]+
Regex101 示例
它是如何在CS中使用的
string strText = " TestWord asdfDasdf ABCDef";
string[] matches = Regex.Matches(strText, @"[A-Z][a-z]+|[A-Z]+(?=[A-Z][a-z])|[a-z]+|[A-Z]+")
.Cast<Match>()
.Select(m => m.Value)
.ToArray();
string result = String.Join(" ", matches);
result
='Test Word asdf Dasdf ABC Def'
它的工作原理
在示例字符串中:
TestWord qwerDasdf
ABCTest Testing ((*&^%$CamelCase!"£$%^^))
asdfAasdf
AaBbbCD
[A-Z][a-z]+
匹配:
- [0-4]
Test
- [4-8]
Word
- [13-18]
Dasdf
- [22-26]
Test
- [27-34]
Testing
- [45-50]
Camel
- [50-54]
Case
- [68-73]
Aasdf
- [74-76]
Aa
- [76-79]
Bbb
[A-Z]+(?=[A-Z][a-z])
匹配:
- [19-22]
ABC
[a-z]+
匹配:
- [9-13]
qwer
- [64-68]
asdf
[A-Z]+
匹配:
- [79-81]
CD
这是我的尝试:
(?<!^|'b|'p{Lu})'p{Lu}+(?='p{Ll}|'b)|(?<!^'p{Lu}*|'b)'p{Lu}(?='p{Ll}|(?<!'p{Lu}*)'b)
此正则表达式可以与Regex.Replace
和 $0
一起用作替换字符串。
Regex.Replace(value, @"(?<!^|'b|'p{Lu})'p{Lu}+(?='p{Ll}|'b)|(?<!^'p{Lu}*|'b)'p{Lu}(?='p{Ll}|(?<!'p{Lu}*)'b)", " $0", RegexOptions.Compiled);
参见演示
Regex解释:
- 包含两个备选方案,用于说明小写字母前后的大写字母链
(?<!^|'b|'p{Lu})'p{Lu}+(?='p{Ll}|'b)
-第一个匹配前面没有字符串开头、单词边界或另一个大写字母,后面跟着小写字母或单词边界的大写字母的选项(?<!^'p{Lu}*|'b)'p{Lu}(?='p{Ll}|(?<!'p{Lu}*)'b)
-第二个备选方案,它匹配一个没有以字符串开头的大写字母,字符串后面有可选的大写字母或单词边界,后面有小写字母或单词边境,单词边界前面没有可选的大写字符
您有使用Regex的要求吗?老实说,我根本不会用Regex。它们很难调试,可读性也不强。
- 有时你也会遇到这样的乐趣:Regex问题:IsMatch方法永远不会返回
- 上面的正则表达式不会处理unicode的奇妙世界,例如Cyrillics(http://en.wikipedia.org/wiki/Cyrillic_script)(并不是说你的特定问题领域可能需要这个,而是为了完整性…(
我会选择一种小型、可重复使用、易于测试的扩展方法:
class Program
{
static void Main(string[] args)
{
string[] inputs = new[]
{
"ABCTest",
"HelloWorld",
"testTest$Test",
"aaҚbb"
};
var output = inputs.Select(x => x.SplitWithSpaces(CultureInfo.CurrentUICulture));
foreach (string x in output)
{
Console.WriteLine(x);
}
Console.Read();
}
}
public static class StringExtensions
{
public static bool IsLowerCase(this TextInfo textInfo, char input)
{
return textInfo.ToLower(input) == input;
}
public static string SplitWithSpaces(this string input, CultureInfo culture = null)
{
if (culture == null)
{
culture = CultureInfo.InvariantCulture;
}
TextInfo textInfo = culture.TextInfo;
StringBuilder sb = new StringBuilder(input);
for (int i = 1; i < sb.Length; i++)
{
int previous = i - 1;
if (textInfo.IsLowerCase(sb[previous]))
{
int insertLocation = previous - 1;
if (insertLocation > 0)
{
sb.Insert(insertLocation, ' ');
}
while (i < sb.Length && textInfo.IsLowerCase(sb[i]))
{
i++;
}
}
}
return sb.ToString();
}
}