Ajouter des espaces avant les lettres majuscules

Étant donné la chaîne “ThisSsortingngHasNoSpacesButItDoesHaveCapitals”, quel est le meilleur moyen d’append des espaces avant les majuscules. Donc, la chaîne de fin serait “Cette chaîne n’a pas d’espaces mais elle a des capitales”

Voici ma tentative avec un RegEx

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

Les expressions rationnelles fonctionneront bien (j’ai même voté pour Martin Browns), mais elles sont chères (et personnellement, je trouve tout modèle plus long que quelques caractères trop obtus)

Cette fonction

 ssortingng AddSpacesToSentence(ssortingng text, bool preserveAcronyms) { if (ssortingng.IsNullOrWhiteSpace(text)) return ssortingng.Empty; SsortingngBuilder newText = new SsortingngBuilder(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(); } 

Je le ferai 100 000 fois en 2 968 750 ticks, le regex prendra 25 000 000 ticks (et ce sera avec le regex compilé).

C'est mieux, pour une valeur donnée de mieux (c'est-à-dire plus rapide), mais c'est plus de code à maintenir. "Mieux" est souvent un compromis entre des exigences concurrentes.

J'espère que cela t'aides 🙂

Mettre à jour
C'est un bon bout de temps depuis que j'ai regardé cela, et je me suis juste rendu compte que les timings n'avaient pas été mis à jour depuis que le code avait changé (il changeait seulement un peu).

Sur une chaîne avec 'Abbbbbbbbb' répétée 100 fois (soit 1 000 octets), une exécution de 100 000 conversions prend la fonction codée à la main 4 517 177 mesures et la Regex ci-dessous prend 59 435 719 pour exécuter la fonction Regex.

Mise à jour 2 Prise en compte des acronymes? Ça va maintenant! La logique de l’état if est assez obscure, comme vous pouvez le voir en l’étendant à cela ...

 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(' '); 

... n'aide pas du tout!

Voici la méthode simple et originale qui ne vous préoccupe pas des acronymes

 ssortingng AddSpacesToSentence(ssortingng text) { if (ssortingng.IsNullOrWhiteSpace(text)) return ""; SsortingngBuilder newText = new SsortingngBuilder(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(); } 

Votre solution a un problème car elle place un espace avant la première lettre T pour

 " This Ssortingng..." instead of "This Ssortingng..." 

Pour contourner ce problème, recherchez également la lettre minuscule qui le précède, puis insérez l’espace au milieu:

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

Edit 1:

Si vous utilisez @"(\p{Ll})(\p{Lu})" il captera également les caractères accentués.

Edit 2:

Si vos chaînes peuvent contenir des acronymes, vous pouvez utiliser ceci:

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

Donc “DriveIsSCSICompatible” devient “Drive Is SCSI Compatible”

N’a pas testé les performances, mais ici en une ligne avec linq:

 var val = "ThisIsASsortingngToTest"; val = ssortingng.Concat(val.Select(x => Char.IsUpper(x) ? " " + x : x.ToSsortingng())).TrimStart(' '); 

Je sais que c’est un ancien, mais c’est une extension que j’utilise quand j’ai besoin de faire ceci:

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

Cela vous permettra d’utiliser MyCasedSsortingng.ToSentence()

Bienvenue chez Unicode

Toutes ces solutions sont essentiellement mauvaises pour le texte moderne. Vous devez utiliser quelque chose qui comprend le cas. Comme Bob a demandé d’autres langues, je donnerai un couple pour Perl.

Je propose quatre solutions, allant du pire au meilleur. Seul le meilleur a toujours raison. Les autres ont des problèmes. Voici un test pour vous montrer ce qui fonctionne et ce qui ne fonctionne pas, et où. J’ai utilisé des traits de soulignement pour que vous puissiez voir où les espaces ont été placés, et j’ai marqué comme étant faux tout ce qui est bien.

 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 

BTW, presque tout le monde ici a choisi la première façon, celle marquée “pire”. Quelques-uns ont choisi la deuxième voie, marquée “OK”. Mais personne d’autre avant moi ne vous a montré comment faire la “meilleure” ou la “meilleure” approche.

Voici le programme de test avec ses quatre méthodes:

 #!/usr/bin/env perl use utf8; use ssortingct; 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 ssortingng with those values in them: my @ssortingngs = 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 (@ssortingngs) { 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; } 

Lorsque vous pouvez obtenir le même résultat que le "meilleur" de cet dataset, vous saurez que vous l'avez correctement fait. Jusque là, vous ne l'avez pas fait. Personne d'autre n'a fait mieux que "Ok", et la plupart l'ont fait "pire". J'ai hâte de voir quelqu'un poster le bon code ℂ♯.

Je remarque que le code de mise en évidence de StackOverflow est misérablement stoopid. Ils font tout le même vieux boiteux que (le plus mais pas tous) des autres approches pauvres mentionnées ici. N'est-il pas temps de mettre de l'ASCII au repos? Cela n'a plus de sens, et prétendre que tout ce que vous avez est tout simplement faux. Cela fait du mauvais code.

Je me suis efforcé de créer une méthode d’extension simple basée sur le code de Binary Worrier, qui traitera correctement les acronymes et qui est reproductible (les mots déjà espacés ne seront pas modifiés). Voici mon résultat.

 public static ssortingng UnPascalCase(this ssortingng text) { if (ssortingng.IsNullOrWhiteSpace(text)) return ""; var newText = new SsortingngBuilder(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.ToSsortingng(); } 

Voici les cas de tests unitaires que cette fonction passe. J’ai ajouté la plupart des cas suggérés par tchrist à cette liste. Les trois de celles-ci ne passent pas (deux ne sont que des chiffres romains):

 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, j’ai utilisé votre code suggéré, et c’est plutôt bon, je n’ai qu’un petit ajout à cela:

 public static ssortingng AddSpacesToSentence(ssortingng text) { if (ssortingng.IsNullOrEmpty(text)) return ""; SsortingngBuilder newText = new SsortingngBuilder(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(); } 

J'ai ajouté une condition !char.IsUpper(text[i - 1]) . Cela corrigeait un bug qui faisait que quelque chose comme 'AverageNOX' devenait 'Average NO X', ce qui est évidemment faux, car il fallait lire 'Average NOX'.

Malheureusement, cela a toujours le bogue que si vous avez le texte "FromAStart", vous obtiendrez "From AStart".

Avez-vous des idées sur ce problème?

Voici la mienne:

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

Assurez-vous de ne pas mettre d’espaces au début de la chaîne, mais de les placer entre des majuscules consécutives. Certaines des réponses ne concernent pas l’un ou l’autre de ces points. Il existe d’autres méthodes que les regex, mais si vous préférez les utiliser, essayez ceci:

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

Le \B est un \b négatif, donc il représente une limite de non-mot. Cela signifie que le modèle correspond à “Y” dans XYzabc , mais pas dans Yzabc ou X Yzabc . En petit bonus, vous pouvez l’utiliser sur une chaîne avec des espaces et elle ne les doublera pas.

Ce que vous avez fonctionne parfaitement. N’oubliez pas de réaffecter la value à la valeur de retour de cette fonction.

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

Voici comment vous pouvez le faire en 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 

Cette regex place un caractère d’espace devant chaque lettre majuscule:

 using System.Text.RegularExpressions; const ssortingng mySsortingngWithoutSpaces = "ThisIsASsortingngWithoutSpaces"; var mySsortingngWithSpaces = Regex.Replace(mySsortingngWithoutSpaces, "([AZ])([az]*)", " $1$2"); 

Attention à l’espace devant “$ 1 $ 2”, c’est ce qui va se faire.

C’est le résultat:

 "This Is A Ssortingng Without Spaces" 

Inspiré de @MartinBrown, deux lignes de regex simple, qui résoudront votre nom, y compris Acyronyms dans la chaîne.

 public ssortingng ResolveName(ssortingng name) { var tmpDisplay = Regex.Replace(name, "([^AZ ])([AZ])", "$1 $2"); return Regex.Replace(tmpDisplay, "([AZ]+)([AZ][^AZ$])", "$1 $2").Trim(); } 
 replaceAll("(?<=[^^\\p{Uppercase}])(?=[\\p{Uppercase}])"," "); 
 static ssortingng AddSpacesToColumnName(ssortingng columnCaption) { if (ssortingng.IsNullOrWhiteSpace(columnCaption)) return ""; SsortingngBuilder newCaption = new SsortingngBuilder(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(); } 

En Ruby, via Regexp:

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

J’ai pris Kevin Ssortingkers excellente solution et converti en VB. Depuis que je suis verrouillé dans .NET 3.5, j’ai également dû écrire IsNullOrWhiteSpace. Cela passe tous ses tests.

  Public Function IsNullOrWhiteSpace(value As Ssortingng) 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  Public Function UnPascalCase(text As Ssortingng) As Ssortingng If text.IsNullOrWhiteSpace Then Return Ssortingng.Empty End If Dim newText = New SsortingngBuilder() 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.ToSsortingng() End Function 

En plus de la réponse de Martin Brown, j’avais aussi un problème avec les chiffres. Par exemple: “Location2” ou “Jan22” doivent être “Emplacement 2” et “Jan 22” respectivement.

Voici mon expression régulière pour le faire, en utilisant la réponse de Martin Brown:

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

Voici quelques sites intéressants pour comprendre ce que chaque partie signifie également:

Analyseur d'expression régulière basé sur Java (mais fonctionne pour la plupart des regex .net)

Analyseur basé sur les scripts d'action

La regex ci-dessus ne fonctionnera pas sur le site du script d'action à moins que vous ne remplaciez tous les \p{Ll} par [az] , le \p{Lu} par [AZ] et \p{Nd} par [0-9] .

Voici ma solution, basée sur la suggestion et la construction de Binary Worriers dans les commentaires de Richard Priddys, mais en prenant également en compte le fait que des espaces peuvent exister dans la chaîne fournie.

 public ssortingng AddSpacesBeforeUpperCase(ssortingng nonSpacedSsortingng) { if (ssortingng.IsNullOrEmpty(nonSpacedSsortingng)) return ssortingng.Empty; SsortingngBuilder newText = new SsortingngBuilder(nonSpacedSsortingng.Length * 2); newText.Append(nonSpacedSsortingng[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(); } 

Pour ceux qui recherchent une fonction C ++ répondant à cette même question, vous pouvez utiliser les éléments suivants. Ceci est modélisé d’après la réponse donnée par @Binary Worrier. Cette méthode conserve uniquement les acronymes automatiquement.

 using namespace std; void AddSpacesToSentence(ssortingng& testSsortingng) ssortingngstream 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; 

Les chaînes de tests que j'ai utilisées pour cette fonction et les résultats sont les suivants:

  • "Bonjour tout le monde" -> "Bonjour tout le monde"
  • "HelloWorld" -> "Hello World"
  • "HelloABCWorld" -> "Bonjour ABC World"
  • "HelloWorldABC" -> "Hello World ABC"
  • "ABCHelloWorld" -> "ABC Hello World"
  • "ABC HELLO WORLD" -> "ABC HELLO WORLD"
  • "ABCHELLOWORLD" -> "ABCHELLOWORLD"
  • "A" -> "A"

Une solution C # pour une chaîne d’entrée composée uniquement de caractères ASCII. Le regex incorpore un lookbehind négatif pour ignorer une lettre majuscule (majuscule) qui apparaît au début de la chaîne. Utilise Regex.Replace () pour renvoyer la chaîne souhaitée.

Voir aussi la démo regex101.com .

 using System; using System.Text.RegularExpressions; public class RegexExample { public static void Main() { var text = "ThisSsortingngHasNoSpacesButItDoesHaveCapitals"; // Use negative lookbehind to match all capital letters // that do not appear at the beginning of the ssortingng. var pattern = "(? 

Production attendue:

 Input: [ThisSsortingngHasNoSpacesButItDoesHaveCapitals] Output: [This Ssortingng Has No Spaces But It Does Have Capitals] 

Mise à jour: Voici une variante qui traitera également les acronymes (séquences de lettres majuscules).

Voir également la démo regex101.com et la démo ideone.com .

 using System; using System.Text.RegularExpressions; public class RegexExample { public static void Main() { var text = "ThisSsortingngHasNoSpacesASCIIButItDoesHaveCapitalsLINQ"; // 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); } } 

Production attendue:

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

La question est un peu ancienne, mais de nos jours, il existe une bibliothèque intéressante sur Nuget qui fait exactement cela, ainsi que de nombreuses autres conversions en texte lisible par l’homme.

Découvrez Humanizer sur GitHub ou Nuget.

Exemple

 "PascalCaseInputSsortingngIsTurnedIntoSentence".Humanize() => "Pascal case input ssortingng is turned into sentence" "Underscored_input_ssortingng_is_turned_into_sentence".Humanize() => "Underscored input ssortingng is turned into sentence" "Underscored_input_Ssortingng_is_turned_INTO_sentence".Humanize() => "Underscored input Ssortingng is turned INTO sentence" // acronyms are left intact "HTML".Humanize() => "HTML" 

Voici une solution plus complète qui ne met pas les espaces devant les mots:

Note: J’ai utilisé plusieurs regexs (pas concis mais cela va aussi gérer les acronymes et les mots à une lettre)

 Dim s As Ssortingng = "ThisSsortingngHasNoSpacesButItDoesHaveCapitals" 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 

Dans :

 "ThisSsortingngHasNoSpacesButItDoesHaveCapitals" "IAmNotAGoat" "LOLThatsHilarious!" "ThisIsASMSMessage" 

Out :

 "This Ssortingng 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.) 

Toutes les réponses précédentes semblaient trop compliquées.

J’avais une chaîne qui avait un mélange de majuscules et _ si utilisé, ssortingng.Replace () pour créer le _, “” et utilisait ce qui suit pour append un espace aux majuscules.

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

Inspiré par la réponse binary Worrier, je me suis penchée là-dessus.

Voici le résultat:

 ///  /// Ssortingng Extension Method /// Adds white space to ssortingngs based on Upper Case Letters ///  ///  /// strIn => "HateJPMorgan" /// preserveAcronyms false => "Hate JP Morgan" /// preserveAcronyms true => "Hate JPMorgan" ///  /// to evaluate /// determines saving acronyms (Optional => false)  public static ssortingng AddSpaces(this ssortingng strIn, bool preserveAcronyms = false) { if (ssortingng.IsNullOrWhiteSpace(strIn)) return Ssortingng.Empty; var ssortingngBuilder = new SsortingngBuilder(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(); } 

A effectué des tests en utilisant un chronomètre exécutant 10000000 itérations et différentes longueurs et combinaisons de chaînes.

En moyenne 50% (peut-être un peu plus) plus rapide que la réponse binary Worrier.

Cela semble être une bonne opportunité pour Aggregate . Ceci est conçu pour être lisible, pas nécessairement particulièrement rapide.

 someSsortingng .Aggregate( new SsortingngBuilder(), (str, ch) => { if (char.IsUpper(ch) && str.Length > 0) str.Append(" "); str.Append(ch); return str; } ).ToSsortingng(); 
  private ssortingng GetProperName(ssortingng Header) { if (Header.ToCharArray().Where(c => Char.IsUpper(c)).Count() == 1) { return Header; } else { ssortingng ReturnHeader = Header[0].ToSsortingng(); for(int i=1; i 

Celui-ci comprend des acronymes et des acronymes pluriels et est un peu plus rapide que la réponse acceptée:

 public ssortingng Sentencify(ssortingng value) { if (ssortingng.IsNullOrWhiteSpace(value)) return ssortingng.Empty; ssortingng final = ssortingng.Empty; for (int i = 0; i < value.Length; i++) { if (i != 0 && Char.IsUpper(value[i])) { if (!Char.IsUpper(value[i - 1])) final += " "; else if (i < (value.Length - 1)) { if (!Char.IsUpper(value[i + 1]) && !((value.Length >= i && value[i + 1] == 's') || (value.Length >= i + 1 && value[i + 1] == 'e' && value[i + 2] == 's'))) final += " "; } } final += value[i]; } return final; } 

Passe ces tests:

 ssortingng test1 = "RegularOTs"; ssortingng test2 = "ThisSsortingngHasNoSpacesASCIIButItDoesHaveCapitalsLINQ"; ssortingng test3 = "ThisSsortingngHasNoSpacesButItDoesHaveCapitals"; 

An implementation with fold , also known as Aggregate :

  public static ssortingng SpaceCapitals(this ssortingng arg) => new ssortingng(arg.Aggregate(new List(), (accum, x) => { if (Char.IsUpper(x) && accum.Any() && // prevent double spacing accum.Last() != ' ' && // prevent spacing acronyms (ASCII, SCSI) !Char.IsUpper(accum.Last())) { accum.Add(' '); } accum.Add(x); return accum; }).ToArray()); 

In addition to the request, this implementation correctly saves leading, inner, trailing spaces and acronyms, for example,

 " SpacedWord " => " Spaced Word ", "Inner Space" => "Inner Space", "SomeACRONYM" => "Some ACRONYM".