大写字母前加空格

给定string“ThisStringHasNoSpacesButItDoesHaveCapitals”什么是在大写字母之前添加空格的最佳方法。 所以结束string将是“这个string没有空间,但它有首都”

这是我的RegEx的尝试

System.Text.RegularExpressions.Regex.Replace(value, "[AZ]", " $0") 

正则expression式将工作正常(我甚至投了马丁布朗答案),但他们是昂贵的(我个人发现任何模式比几个字符长得过分钝)

这个function

 string AddSpacesToSentence(string text, bool preserveAcronyms) { if (string.IsNullOrWhiteSpace(text)) return string.Empty; StringBuilder newText = new StringBuilder(text.Length * 2); newText.Append(text[0]); for (int i = 1; i < text.Length; i++) { if (char.IsUpper(text[i])) if ((text[i - 1] != ' ' && !char.IsUpper(text[i - 1])) || (preserveAcronyms && char.IsUpper(text[i - 1]) && i < text.Length - 1 && !char.IsUpper(text[i + 1]))) newText.Append(' '); newText.Append(text[i]); } return newText.ToString(); } 

将在2,968,750个刻度中执行10万次,正则expression式将需要25,000,000次刻度(以及编译后的正则expression式)。

更好的是,给定的值更好(即更快),但更多的代码需要维护。 “更好”往往是妥协的竞争要求。

希望这可以帮助 :)

更新
自从我看了这么长时间以来,我只是意识到自从代码改变以来,时序并没有被更新(它只是变了一点)。

在一个有“Abbbbbbbbb”的string重复100次(即1,000字节)的情况下,100,000次转换的结果是手工编码函数4,517,177,而下面的正则expression式需要59,435,719次,这使得手动编码函数占用了7.6%的时间正则expression式。

更新2是否将缩略语考虑在内? 现在会! if语句的逻辑很模糊,你可以看到扩展到这个…

 if (char.IsUpper(text[i])) if (char.IsUpper(text[i - 1])) if (preserveAcronyms && i < text.Length - 1 && !char.IsUpper(text[i + 1])) newText.Append(' '); else ; else if (text[i - 1] != ' ') newText.Append(' '); 

…根本没有帮助!

这是原先简单的方法,不用担心缩写

 string AddSpacesToSentence(string text) { if (string.IsNullOrWhiteSpace(text)) return ""; StringBuilder newText = new StringBuilder(text.Length * 2); newText.Append(text[0]); for (int i = 1; i < text.Length; i++) { if (char.IsUpper(text[i]) && text[i - 1] != ' ') newText.Append(' '); newText.Append(text[i]); } return newText.ToString(); } 

您的解决scheme有一个问题,因为它在第一个字母T之前放置一个空格,所以您可以得到

 " This String..." instead of "This String..." 

为了绕过这个小写字母前面的字母,然后在中间插入空格:

 newValue = Regex.Replace(value, "([az])([AZ])", "$1 $2"); 

编辑1:

如果您使用@"(\p{Ll})(\p{Lu})"它也会选取重音字符。

编辑2:

如果你的string可以包含首字母缩略词,你可能想要使用这个:

 newValue = Regex.Replace(value, @"((?<=\p{Ll})\p{Lu})|((?!\A)\p{Lu}(?>\p{Ll}))", " $0"); 

所以“DriveIsSICICompatible”变成“Drive is SCSI Compatible”

没有testing性能,但在这里与linq的一行:

 var val = "ThisIsAStringToTest"; val = string.Concat(val.Select(x => Char.IsUpper(x) ? " " + x : x.ToString())).TrimStart(' '); 

我知道这是一个老的,但这是我使用的扩展,当我需要这样做:

 public static class Extensions { public static string ToSentence( this string Input ) { return new string(Input.ToCharArray().SelectMany((c, i) => i > 0 && char.IsUpper(c) ? new char[] { ' ', c } : new char[] { c }).ToArray()); } } 

这将允许你使用MyCasedString.ToSentence()

欢迎来到Unicode

所有这些解决scheme对现代文本来说都是错误的 你需要使用理解大小写的东西。 由于鲍勃要求其他语言,我会给一对Perl的。

我提供了四种解决scheme,从最差到最好。 只有最好的一个永远是对的。 其他人有问题。 这是一个testing运行,告诉你什么可行,什么不可以,以及在哪里。 我使用了下划线,以便您可以看到空格的位置,而且我已经标记为任何错误的东西。

 Testing TheLoneRanger Worst: The_Lone_Ranger Ok: The_Lone_Ranger Better: The_Lone_Ranger Best: The_Lone_Ranger Testing MountMᶜKinleyNationalPark [WRONG] Worst: Mount_MᶜKinley_National_Park [WRONG] Ok: Mount_MᶜKinley_National_Park [WRONG] Better: Mount_MᶜKinley_National_Park Best: Mount_Mᶜ_Kinley_National_Park Testing ElÁlamoTejano [WRONG] Worst: ElÁlamo_Tejano Ok: El_Álamo_Tejano Better: El_Álamo_Tejano Best: El_Álamo_Tejano Testing TheÆvarArnfjörðBjarmason [WRONG] Worst: TheÆvar_ArnfjörðBjarmason Ok: The_Ævar_Arnfjörð_Bjarmason Better: The_Ævar_Arnfjörð_Bjarmason Best: The_Ævar_Arnfjörð_Bjarmason Testing IlCaffèMacchiato [WRONG] Worst: Il_CaffèMacchiato Ok: Il_Caffè_Macchiato Better: Il_Caffè_Macchiato Best: Il_Caffè_Macchiato Testing MisterDženanLjubović [WRONG] Worst: MisterDženanLjubović [WRONG] Ok: MisterDženanLjubović Better: Mister_Dženan_Ljubović Best: Mister_Dženan_Ljubović Testing OleKingHenryⅧ [WRONG] Worst: Ole_King_HenryⅧ [WRONG] Ok: Ole_King_HenryⅧ [WRONG] Better: Ole_King_HenryⅧ Best: Ole_King_Henry_Ⅷ Testing CarlosⅤºElEmperador [WRONG] Worst: CarlosⅤºEl_Emperador [WRONG] Ok: CarlosⅤº_El_Emperador [WRONG] Better: CarlosⅤº_El_Emperador Best: Carlos_Ⅴº_El_Emperador 

顺便说一句,这里几乎所有人都select了第一种方式,一个标记为“最差”。 有几个select了第二种方式,标记为“OK”。 但是在我之前没有人告诉你如何做“更好”或“最好”的方法。

这里有四个方法的testing程序:

 #!/usr/bin/env perl use utf8; use strict; use warnings; # First I'll prove these are fine variable names: my ( $TheLoneRanger , $MountMᶜKinleyNationalPark , $ElÁlamoTejano , $TheÆvarArnfjörðBjarmason , $IlCaffèMacchiato , $MisterDženanLjubović , $OleKingHenryⅧ , $CarlosⅤºElEmperador , ); # Now I'll load up some string with those values in them: my @strings = qw{ TheLoneRanger MountMᶜKinleyNationalPark ElÁlamoTejano TheÆvarArnfjörðBjarmason IlCaffèMacchiato MisterDženanLjubović OleKingHenryⅧ CarlosⅤºElEmperador }; my($new, $best, $ok); my $mask = " %10s %-8s %s\n"; for my $old (@strings) { print "Testing $old\n"; ($best = $old) =~ s/(?<=\p{Lowercase})(?=[\p{Uppercase}\p{Lt}])/_/g; ($new = $old) =~ s/(?<=[az])(?=[AZ])/_/g; $ok = ($new ne $best) && "[WRONG]"; printf $mask, $ok, "Worst:", $new; ($new = $old) =~ s/(?<=\p{Ll})(?=\p{Lu})/_/g; $ok = ($new ne $best) && "[WRONG]"; printf $mask, $ok, "Ok:", $new; ($new = $old) =~ s/(?<=\p{Ll})(?=[\p{Lu}\p{Lt}])/_/g; $ok = ($new ne $best) && "[WRONG]"; printf $mask, $ok, "Better:", $new; ($new = $old) =~ s/(?<=\p{Lowercase})(?=[\p{Uppercase}\p{Lt}])/_/g; $ok = ($new ne $best) && "[WRONG]"; printf $mask, $ok, "Best:", $new; } 

当你在这个数据集上得分与“最佳”相同时,你就会知道你做得正确。 在此之前,你还没有。 这里没有其他人做得比“好”好多了,大部分人都做得“差”。 我期待看到有人张贴正确的ℂ♯代码。

我注意到,StackOverflow的高亮代码再次悲惨地stoopid。 他们把这里所提到的其他穷途径(大多数,但不是全部)做成同样的老瘸子。 不是很久以前把ASCII码放到rest的时间了吗? 它不再有意义了,假装你所拥有的只是错误的。 它会导致错误的代码。

我着手做一个基于Binary Worrier代码的简单扩展方法,它将正确处理缩略词,并且是可重复的(不会破坏已经分开的单词)。 这是我的结果。

 public static string UnPascalCase(this string text) { if (string.IsNullOrWhiteSpace(text)) return ""; var newText = new StringBuilder(text.Length * 2); newText.Append(text[0]); for (int i = 1; i < text.Length; i++) { var currentUpper = char.IsUpper(text[i]); var prevUpper = char.IsUpper(text[i - 1]); var nextUpper = (text.Length > i + 1) ? char.IsUpper(text[i + 1]) || char.IsWhiteSpace(text[i + 1]): prevUpper; var spaceExists = char.IsWhiteSpace(text[i - 1]); if (currentUpper && !spaceExists && (!nextUpper || !prevUpper)) newText.Append(' '); newText.Append(text[i]); } return newText.ToString(); } 

这里是这个函数传递的unit testing用例。 我把大多数特里克斯的build议案例添加到这个列表中。 其中三个没有通过(两个是罗马数字)被注释掉:

 Assert.AreEqual("For You And I", "ForYouAndI".UnPascalCase()); Assert.AreEqual("For You And The FBI", "ForYouAndTheFBI".UnPascalCase()); Assert.AreEqual("A Man A Plan A Canal Panama", "AManAPlanACanalPanama".UnPascalCase()); Assert.AreEqual("DNS Server", "DNSServer".UnPascalCase()); Assert.AreEqual("For You And I", "For You And I".UnPascalCase()); Assert.AreEqual("Mount Mᶜ Kinley National Park", "MountMᶜKinleyNationalPark".UnPascalCase()); Assert.AreEqual("El Álamo Tejano", "ElÁlamoTejano".UnPascalCase()); Assert.AreEqual("The Ævar Arnfjörð Bjarmason", "TheÆvarArnfjörðBjarmason".UnPascalCase()); Assert.AreEqual("Il Caffè Macchiato", "IlCaffèMacchiato".UnPascalCase()); //Assert.AreEqual("Mister Dženan Ljubović", "MisterDženanLjubović".UnPascalCase()); //Assert.AreEqual("Ole King Henry Ⅷ", "OleKingHenryⅧ".UnPascalCase()); //Assert.AreEqual("Carlos Ⅴº El Emperador", "CarlosⅤºElEmperador".UnPascalCase()); Assert.AreEqual("For You And The FBI", "For You And The FBI".UnPascalCase()); Assert.AreEqual("A Man A Plan A Canal Panama", "A Man A Plan A Canal Panama".UnPascalCase()); Assert.AreEqual("DNS Server", "DNS Server".UnPascalCase()); Assert.AreEqual("Mount Mᶜ Kinley National Park", "Mount Mᶜ Kinley National Park".UnPascalCase()); 

Binary Worrier,我已经使用了你的build议代码,它相当好,我只有一个小的补充:

 public static string AddSpacesToSentence(string text) { if (string.IsNullOrEmpty(text)) return ""; StringBuilder newText = new StringBuilder(text.Length * 2); newText.Append(text[0]); for (int i = 1; i < result.Length; i++) { if (char.IsUpper(result[i]) && !char.IsUpper(result[i - 1])) { newText.Append(' '); } else if (i < result.Length) { if (char.IsUpper(result[i]) && !char.IsUpper(result[i + 1])) newText.Append(' '); } newText.Append(result[i]); } return newText.ToString(); } 

我添加了一个条件!char.IsUpper(text[i - 1]) 。 这修正了一个错误,会导致像'AverageNOX'的东西变成'Average NO X',这显然是错误的,因为它应该是'Average NOX'。

不幸的是,这仍然有一个错误,如果你有文本“FromAStart”,你会得到“From AStart”。

任何想法解决这个问题?

这是我的:

 private string SplitCamelCase(string s) { Regex upperCaseRegex = new Regex(@"[AZ]{1}[az]*"); MatchCollection matches = upperCaseRegex.Matches(s); List<string> words = new List<string>(); foreach (Match match in matches) { words.Add(match.Value); } return String.Join(" ", words.ToArray()); } 

确保你没有在string的开始处放置空格,但是你要把它们放在连续的大写字母之间。 这里的一些答案没有解决这些问题中的一个或两个问题。 除了正则expression式还有其他的方法,但是如果你喜欢使用它,试试这个:

 Regex.Replace(value, @"\B[AZ]", " $0") 

\B是否定的\b ,所以它代表了一个非字边界。 这意味着模式在XYzabc匹配“Y”,但在YzabcX YzabcX Yzabc 。 作为一个小小的奖励,你可以在一个带有空格的string上使用它,并且不会加倍。

你有什么完美的作品。 只记得重新value给这个函数的返回值。

 value = System.Text.RegularExpressions.Regex.Replace(value, "[AZ]", " $0"); 

这里是你如何在SQL中做到这一点

 create FUNCTION dbo.PascalCaseWithSpace(@pInput AS VARCHAR(MAX)) RETURNS VARCHAR(MAX) BEGIN declare @output varchar(8000) set @output = '' Declare @vInputLength INT Declare @vIndex INT Declare @vCount INT Declare @PrevLetter varchar(50) SET @PrevLetter = '' SET @vCount = 0 SET @vIndex = 1 SET @vInputLength = LEN(@pInput) WHILE @vIndex <= @vInputLength BEGIN IF ASCII(SUBSTRING(@pInput, @vIndex, 1)) = ASCII(Upper(SUBSTRING(@pInput, @vIndex, 1))) begin if(@PrevLetter != '' and ASCII(@PrevLetter) = ASCII(Lower(@PrevLetter))) SET @output = @output + ' ' + SUBSTRING(@pInput, @vIndex, 1) else SET @output = @output + SUBSTRING(@pInput, @vIndex, 1) end else begin SET @output = @output + SUBSTRING(@pInput, @vIndex, 1) end set @PrevLetter = SUBSTRING(@pInput, @vIndex, 1) SET @vIndex = @vIndex + 1 END return @output END 

这个正则expression式在每个大写字母的前面放置一个空格字符:

 using System.Text.RegularExpressions; const string myStringWithoutSpaces = "ThisIsAStringWithoutSpaces"; var myStringWithSpaces = Regex.Replace(myStringWithoutSpaces, "([AZ])([az]*)", " $1$2"); 

注意前面的空间,如果“$ 1 $ 2”,这将是完成的。

这是结果:

 "This Is A String Without Spaces" 
 replaceAll("(?<=[^^\\p{Uppercase}])(?=[\\p{Uppercase}])"," "); 
 static string AddSpacesToColumnName(string columnCaption) { if (string.IsNullOrWhiteSpace(columnCaption)) return ""; StringBuilder newCaption = new StringBuilder(columnCaption.Length * 2); newCaption.Append(columnCaption[0]); int pos = 1; for (pos = 1; pos < columnCaption.Length-1; pos++) { if (char.IsUpper(columnCaption[pos]) && !(char.IsUpper(columnCaption[pos - 1]) && char.IsUpper(columnCaption[pos + 1]))) newCaption.Append(' '); newCaption.Append(columnCaption[pos]); } newCaption.Append(columnCaption[pos]); return newCaption.ToString(); } 

在Ruby中,通过Regexp:

 "FooBarBaz".gsub(/(?!^)(?=[AZ])/, ' ') # => "Foo Bar Baz" 

我采取了凯文Strikers优秀的解决scheme,并转换为VB。 由于我被locking到.NET 3.5,我还必须写IsNullOrWhiteSpace。 这通过了他所有的testing。

 <Extension()> Public Function IsNullOrWhiteSpace(value As String) As Boolean If value Is Nothing Then Return True End If For i As Integer = 0 To value.Length - 1 If Not Char.IsWhiteSpace(value(i)) Then Return False End If Next Return True End Function <Extension()> Public Function UnPascalCase(text As String) As String If text.IsNullOrWhiteSpace Then Return String.Empty End If Dim newText = New StringBuilder() newText.Append(text(0)) For i As Integer = 1 To text.Length - 1 Dim currentUpper = Char.IsUpper(text(i)) Dim prevUpper = Char.IsUpper(text(i - 1)) Dim nextUpper = If(text.Length > i + 1, Char.IsUpper(text(i + 1)) Or Char.IsWhiteSpace(text(i + 1)), prevUpper) Dim spaceExists = Char.IsWhiteSpace(text(i - 1)) If (currentUpper And Not spaceExists And (Not nextUpper Or Not prevUpper)) Then newText.Append(" ") End If newText.Append(text(i)) Next Return newText.ToString() End Function 

除了Martin Brown的答案之外,我还有一个关于数字的问题。 例如:“位置2”或“Jan22”应分别为“位置2”和“1月22日”。

这是我的正则expression式,使用Martin Brown的答案:

 "((?<=\p{Ll})\p{Lu})|((?!\A)\p{Lu}(?>\p{Ll}))|((?<=[\p{Ll}\p{Lu}])\p{Nd})|((?<=\p{Nd})\p{Lu})" 

这里有几个伟大的网站来搞清楚每个部分的含义:

基于Java的正则expression式分析器(但适用于大多数.NET正则expression式)

基于脚本的分析器

除非用[az]\p{Lu}[AZ]\p{Nd}代替[AZ] ,否则以上正则expression式在动作脚本站点上将不起作用。 [0-9]

这里是我的解决scheme,根据Richard Priddys的build议和build立在Binary Worriers的build议,同时考虑到提供的string中可能存在空白区域,所以它不会在现有的空白区旁边添加空白区域。

 public string AddSpacesBeforeUpperCase(string nonSpacedString) { if (string.IsNullOrEmpty(nonSpacedString)) return string.Empty; StringBuilder newText = new StringBuilder(nonSpacedString.Length * 2); newText.Append(nonSpacedString[0]); for (int i = 1; i < nonSpacedString.Length; i++) { char currentChar = nonSpacedString[i]; // If it is whitespace, we do not need to add another next to it if(char.IsWhiteSpace(currentChar)) { continue; } char previousChar = nonSpacedString[i - 1]; char nextChar = i < nonSpacedString.Length - 1 ? nonSpacedString[i + 1] : nonSpacedString[i]; if (char.IsUpper(currentChar) && !char.IsWhiteSpace(nextChar) && !(char.IsUpper(previousChar) && char.IsUpper(nextChar))) { newText.Append(' '); } else if (i < nonSpacedString.Length) { if (char.IsUpper(currentChar) && !char.IsWhiteSpace(nextChar) && !char.IsUpper(nextChar)) { newText.Append(' '); } } newText.Append(currentChar); } return newText.ToString(); } 

对于任何正在寻找C ++函数的人来说,回答这个问题,你可以使用下面的代码。 这是仿照@Binary Worrier给出的答案。 这种方法只是自动保存缩略语。

 using namespace std; void AddSpacesToSentence(string& testString) stringstream ss; ss << testString.at(0); for (auto it = testString.begin() + 1; it != testString.end(); ++it ) { int index = it - testString.begin(); char c = (*it); if (isupper(c)) { char prev = testString.at(index - 1); if (isupper(prev)) { if (index < testString.length() - 1) { char next = testString.at(index + 1); if (!isupper(next) && next != ' ') { ss << ' '; } } } else if (islower(prev)) { ss << ' '; } } ss << c; } cout << ss.str() << endl; 

我用于这个函数的testingstring,结果是:

  • “helloWorld” – >“hello world”
  • “HelloWorld” – >“Hello World”
  • “HelloABCWorld” – >“你好ABC世界”
  • “HelloWorldABC” – >“Hello World ABC”
  • “ABCHelloWorld” – >“ABC Hello World”
  • “ABC HELLO WORLD” – >“ABC HELLO WORLD”
  • “ABCHELLOWORLD” – >“ABCHELLOWORLD”
  • “A” – >“A”

用于仅包含ASCII字符的inputstring的C#解决scheme。 正则expression式包含负向后置 ,忽略出现在string开头的大写字母(大写字母)。 使用Regex.Replace()返回所需的string。

另请参阅regex101.com演示 。

 using System; using System.Text.RegularExpressions; public class RegexExample { public static void Main() { var text = "ThisStringHasNoSpacesButItDoesHaveCapitals"; // Use negative lookbehind to match all capital letters // that do not appear at the beginning of the string. var pattern = "(?<!^)([AZ])"; var rgx = new Regex(pattern); var result = rgx.Replace(text, " $1"); Console.WriteLine("Input: [{0}]\nOutput: [{1}]", text, result); } } 

预期产出:

 Input: [ThisStringHasNoSpacesButItDoesHaveCapitals] Output: [This String Has No Spaces But It Does Have Capitals] 

更新:这是一个变体,也将处理首字母缩略词 (大写字母序列)。

另请参阅regex101.com演示和ideone.com演示 。

 using System; using System.Text.RegularExpressions; public class RegexExample { public static void Main() { var text = "ThisStringHasNoSpacesASCIIButItDoesHaveCapitalsLINQ"; // Use positive lookbehind to locate all upper-case letters // that are preceded by a lower-case letter. var patternPart1 = "(?<=[az])([AZ])"; // Used positive lookbehind and lookahead to locate all // upper-case letters that are preceded by an upper-case // letter and followed by a lower-case letter. var patternPart2 = "(?<=[AZ])([AZ])(?=[az])"; var pattern = patternPart1 + "|" + patternPart2; var rgx = new Regex(pattern); var result = rgx.Replace(text, " $1$2"); Console.WriteLine("Input: [{0}]\nOutput: [{1}]", text, result); } } 

预期产出:

 Input: [ThisStringHasNoSpacesASCIIButItDoesHaveCapitalsLINQ] Output: [This String Has No Spaces ASCII But It Does Have Capitals LINQ] 

这个问题有点古老,但是现在Nuget上有一个很好的库,可以完成这个function,还有许多其他的转换function可以用于人类可读的文本。

在GitHub或Nuget上检查Humanizer 。

 "PascalCaseInputStringIsTurnedIntoSentence".Humanize() => "Pascal case input string is turned into sentence" "Underscored_input_string_is_turned_into_sentence".Humanize() => "Underscored input string is turned into sentence" "Underscored_input_String_is_turned_INTO_sentence".Humanize() => "Underscored input String is turned INTO sentence" // acronyms are left intact "HTML".Humanize() => "HTML" 

这比“接受的答案”更清洁,更快(10万次需要1,290,129个滴答声),并且还包括首字母缩略词:

 public string Sentencify(string value) { if (string.IsNullOrWhiteSpace(value)) return string.Empty; string final = string.Empty; for (int i = 0; i < value.Length; i++) { final += (Char.IsUpper(value[i]) && ((i == 0 || !Char.IsUpper(value[i - 1])) || (i != (value.Length - 1) && !Char.IsUpper(value[i + 1]))) ? " " : "") + value[i]; } return final.TrimStart(' '); } 

这是一个更彻底的解决scheme,不会在语言前放置空格:

注:我已经使用了多个正则expression式(不简单,但它也将处理首字母缩写词和单个字母的单词)

 Dim s As String = "ThisStringHasNoSpacesButItDoesHaveCapitals" s = System.Text.RegularExpressions.Regex.Replace(s, "([az])([AZ](?=[AZ])[az]*)", "$1 $2") s = System.Text.RegularExpressions.Regex.Replace(s, "([AZ])([AZ][az])", "$1 $2") s = System.Text.RegularExpressions.Regex.Replace(s, "([az])([AZ][az])", "$1 $2") s = System.Text.RegularExpressions.Regex.Replace(s, "([az])([AZ][az])", "$1 $2") // repeat a second time 

 "ThisStringHasNoSpacesButItDoesHaveCapitals" "IAmNotAGoat" "LOLThatsHilarious!" "ThisIsASMSMessage" 

输出

 "This String Has No Spaces But It Does Have Capitals" "I Am Not A Goat" "LOL Thats Hilarious!" "This Is ASMS Message" // (Difficult to handle single letter words when they are next to acronyms.) 

灵感来自@MartinBrown,简单的正则expression式的两行,这将解决你的名字,包括string中的任何地方的Acyronyms。

 public string ResolveName(string name) { var tmpDisplay = Regex.Replace(name, "([^AZ ])([AZ])", "$1 $2"); return Regex.Replace(tmpDisplay, "([AZ]+)([AZ][^AZ$])", "$1 $2").Trim(); } 

所有以前的回复看起来都太复杂了。

我有一个混合了大写字母和_的string,用string.Replace()来创build_,“”,并用下面的代码在大写字母处添加一个空格。

 for (int i = 0; i < result.Length; i++) { if (char.IsUpper(result[i])) { counter++; if (i > 1) //stops from adding a space at if string starts with Capital { result = result.Insert(i, " "); i++; //Required** otherwise stuck in infinite //add space loop over a single capital letter. } } } 

受到“二元难题”的启发,我对此深表谢意。

结果如下:

 /// <summary> /// String Extension Method /// Adds white space to strings based on Upper Case Letters /// </summary> /// <example> /// strIn => "HateJPMorgan" /// preserveAcronyms false => "Hate JP Morgan" /// preserveAcronyms true => "Hate JPMorgan" /// </example> /// <param name="strIn">to evaluate</param> /// <param name="preserveAcronyms" >determines saving acronyms (Optional => false) </param> public static string AddSpaces(this string strIn, bool preserveAcronyms = false) { if (string.IsNullOrWhiteSpace(strIn)) return String.Empty; var stringBuilder = new StringBuilder(strIn.Length * 2) .Append(strIn[0]); int i; for (i = 1; i < strIn.Length - 1; i++) { var c = strIn[i]; if (Char.IsUpper(c) && (Char.IsLower(strIn[i - 1]) || (preserveAcronyms && Char.IsLower(strIn[i + 1])))) stringBuilder.Append(' '); stringBuilder.Append(c); } return stringBuilder.Append(strIn[i]).ToString(); } 

testing使用秒表运行10000000次迭代以及各种string长度和组合。

平均50%(也许多一点)比Binary Worrier的答案更快。

似乎是一个Aggregate的好机会。 这被devise为可读,不一定特别快。

 someString .Aggregate( new StringBuilder(), (str, ch) => { if (char.IsUpper(ch) && str.Length > 0) str.Append(" "); str.Append(ch); return str; } ).ToString(); 
  private string GetProperName(string Header) { if (Header.ToCharArray().Where(c => Char.IsUpper(c)).Count() == 1) { return Header; } else { string ReturnHeader = Header[0].ToString(); for(int i=1; i<Header.Length;i++) { if (char.IsLower(Header[i-1]) && char.IsUpper(Header[i])) { ReturnHeader += " " + Header[i].ToString(); } else { ReturnHeader += Header[i].ToString(); } } return ReturnHeader; } return Header; }