Quelqu'un aurait-il une bonne Appropriée des Cas de l'algorithme de
Question
Quelqu'un de confiance de Cas ou PCase algorithme (similaire à une fonction UCase ou Supérieur)?Je suis à la recherche de quelque chose qui prend une valeur telle que "GEORGE BURDELL"
ou "george burdell"
et il se transforme en "George Burdell"
.
J'ai une simple celui qui traite les cas simples.L'idéal serait d'avoir quelque chose qui peut gérer les choses comme "O'REILLY"
et de le transformer en "O'Reilly"
, mais je sais que c'est plus difficile.
Je suis principalement axé sur la langue anglaise si cela simplifie les choses.
Mise à JOUR: Je suis à l'aide de C# comme langage, mais je peux convertir à partir de presque rien (en supposant, comme l'existence de la fonctionnalité).
Je suis d'accord que le Mcdonald's scneario est difficile.Je voulais parler de ça avec ma O'Reilly exemple, mais n'a pas dans le post original.
La solution
À moins que j'ai mal compris votre question, je ne pense pas que vous avez besoin pour restaurer votre propre, la classe TextInfo peut le faire pour vous.
using System.Globalization;
CultureInfo.InvariantCulture.TextInfo.ToTitleCase("GeOrGE bUrdEll")
Sera de retour "George Burdell.Et vous pouvez utiliser votre propre culture, si il y a des règles particulières en cause.
Mise à jour: Michael (dans un commentaire à cette réponse) a souligné que cela ne fonctionnera pas si l'entrée est tout en majuscule, puisque la méthode suppose qu'il est un acronyme.Le naïf solution pour cela est de .ToLower() le texte avant de le soumettre à ToTitleCase.
Autres conseils
@Zack:Je vais poster une réponse séparée.
Voici un exemple basé sur kronoz post.
void Main()
{
List<string> names = new List<string>() {
"bill o'reilly",
"johannes diderik van der waals",
"mr. moseley-williams",
"Joe VanWyck",
"mcdonald's",
"william the third",
"hrh prince charles",
"h.r.m. queen elizabeth the third",
"william gates, iii",
"pope leo xii",
"a.k. jennings"
};
names.Select(name => name.ToProperCase()).Dump();
}
// Define other methods and classes here
// http://stackoverflow.com/questions/32149/does-anyone-have-a-good-proper-case-algorithm
public static class ProperCaseHelper {
public static string ToProperCase(this string input) {
if (IsAllUpperOrAllLower(input))
{
// fix the ALL UPPERCASE or all lowercase names
return string.Join(" ", input.Split(' ').Select(word => wordToProperCase(word)));
}
else
{
// leave the CamelCase or Propercase names alone
return input;
}
}
public static bool IsAllUpperOrAllLower(this string input) {
return (input.ToLower().Equals(input) || input.ToUpper().Equals(input) );
}
private static string wordToProperCase(string word) {
if (string.IsNullOrEmpty(word)) return word;
// Standard case
string ret = capitaliseFirstLetter(word);
// Special cases:
ret = properSuffix(ret, "'"); // D'Artagnon, D'Silva
ret = properSuffix(ret, "."); // ???
ret = properSuffix(ret, "-"); // Oscar-Meyer-Weiner
ret = properSuffix(ret, "Mc"); // Scots
ret = properSuffix(ret, "Mac"); // Scots
// Special words:
ret = specialWords(ret, "van"); // Dick van Dyke
ret = specialWords(ret, "von"); // Baron von Bruin-Valt
ret = specialWords(ret, "de");
ret = specialWords(ret, "di");
ret = specialWords(ret, "da"); // Leonardo da Vinci, Eduardo da Silva
ret = specialWords(ret, "of"); // The Grand Old Duke of York
ret = specialWords(ret, "the"); // William the Conqueror
ret = specialWords(ret, "HRH"); // His/Her Royal Highness
ret = specialWords(ret, "HRM"); // His/Her Royal Majesty
ret = specialWords(ret, "H.R.H."); // His/Her Royal Highness
ret = specialWords(ret, "H.R.M."); // His/Her Royal Majesty
ret = dealWithRomanNumerals(ret); // William Gates, III
return ret;
}
private static string properSuffix(string word, string prefix) {
if(string.IsNullOrEmpty(word)) return word;
string lowerWord = word.ToLower();
string lowerPrefix = prefix.ToLower();
if (!lowerWord.Contains(lowerPrefix)) return word;
int index = lowerWord.IndexOf(lowerPrefix);
// If the search string is at the end of the word ignore.
if (index + prefix.Length == word.Length) return word;
return word.Substring(0, index) + prefix +
capitaliseFirstLetter(word.Substring(index + prefix.Length));
}
private static string specialWords(string word, string specialWord)
{
if(word.Equals(specialWord, StringComparison.InvariantCultureIgnoreCase))
{
return specialWord;
}
else
{
return word;
}
}
private static string dealWithRomanNumerals(string word)
{
List<string> ones = new List<string>() { "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" };
List<string> tens = new List<string>() { "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", "C" };
// assume nobody uses hundreds
foreach (string number in ones)
{
if (word.Equals(number, StringComparison.InvariantCultureIgnoreCase))
{
return number;
}
}
foreach (string ten in tens)
{
foreach (string one in ones)
{
if (word.Equals(ten + one, StringComparison.InvariantCultureIgnoreCase))
{
return ten + one;
}
}
}
return word;
}
private static string capitaliseFirstLetter(string word) {
return char.ToUpper(word[0]) + word.Substring(1).ToLower();
}
}
Il y a aussi cette soigné script Perl pour le titre du corps de texte.
http://daringfireball.net/2008/08/title_case_update
#!/usr/bin/perl # This filter changes all words to Title Caps, and attempts to be clever # about *un*capitalizing small words like a/an/the in the input. # # The list of "small words" which are not capped comes from # the New York Times Manual of Style, plus 'vs' and 'v'. # # 10 May 2008 # Original version by John Gruber: # http://daringfireball.net/2008/05/title_case # # 28 July 2008 # Re-written and much improved by Aristotle Pagaltzis: # http://plasmasturm.org/code/titlecase/ # # Full change log at __END__. # # License: http://www.opensource.org/licenses/mit-license.php # use strict; use warnings; use utf8; use open qw( :encoding(UTF-8) :std ); my @small_words = qw( (?<!q&)a an and as at(?!&t) but by en for if in of on or the to v[.]? via vs[.]? ); my $small_re = join '|', @small_words; my $apos = qr/ (?: ['’] [[:lower:]]* )? /x; while ( <> ) { s{\A\s+}{}, s{\s+\z}{}; $_ = lc $_ if not /[[:lower:]]/; s{ \b (_*) (?: ( (?<=[ ][/\\]) [[:alpha:]]+ [-_[:alpha:]/\\]+ | # file path or [-_[:alpha:]]+ [@.:] [-_[:alpha:]@.:/]+ $apos ) # URL, domain, or email | ( (?i: $small_re ) $apos ) # or small word (case-insensitive) | ( [[:alpha:]] [[:lower:]'’()\[\]{}]* $apos ) # or word w/o internal caps | ( [[:alpha:]] [[:alpha:]'’()\[\]{}]* $apos ) # or some other word ) (_*) \b }{ $1 . ( defined $2 ? $2 # preserve URL, domain, or email : defined $3 ? "\L$3" # lowercase small word : defined $4 ? "\u\L$4" # capitalize word w/o internal caps : $5 # preserve other kinds of word ) . $6 }xeg; # Exceptions for small words: capitalize at start and end of title s{ ( \A [[:punct:]]* # start of title... | [:.;?!][ ]+ # or of subsentence... | [ ]['"“‘(\[][ ]* ) # or of inserted subphrase... ( $small_re ) \b # ... followed by small word }{$1\u\L$2}xig; s{ \b ( $small_re ) # small word... (?= [[:punct:]]* \Z # ... at the end of the title... | ['"’”)\]] [ ] ) # ... or of an inserted subphrase? }{\u\L$1}xig; # Exceptions for small words in hyphenated compound words ## e.g. "in-flight" -> In-Flight s{ \b (?<! -) # Negative lookbehind for a hyphen; we don't want to match man-in-the-middle but do want (in-flight) ( $small_re ) (?= -[[:alpha:]]+) # lookahead for "-someword" }{\u\L$1}xig; ## # e.g. "Stand-in" -> "Stand-In" (Stand is already capped at this point) s{ \b (?<!…) # Negative lookbehind for a hyphen; we don't want to match man-in-the-middle but do want (stand-in) ( [[:alpha:]]+- ) # $1 = first word and hyphen, should already be properly capped ( $small_re ) # ... followed by small word (?! - ) # Negative lookahead for another '-' }{$1\u$2}xig; print "$_"; } __END__
Mais il semble que par la bonne affaire que vous entendez..pour les noms de personnes seulement.
J'ai écrit aujourd'hui à mettre en œuvre dans une application que je suis en train de travailler sur.Je pense que ce code est assez explicite avec des commentaires.Ce n'est pas précis à 100% dans tous les cas, mais il sera poignée plus de votre western noms facilement.
Exemples:
mary-jane => Mary-Jane
o'brien => O'Brien
Joël VON WINTEREGG => Joël von Winteregg
jose de la acosta => Jose de la Acosta
Le code est extensible que vous pouvez ajouter à n'importe quelle chaîne de la valeur à la tableaux de à la haut de répondre à vos besoins.Veuillez étudier et d'ajouter une fonction spéciale qui peut être nécessaire.
function name_title_case($str)
{
// name parts that should be lowercase in most cases
$ok_to_be_lower = array('av','af','da','dal','de','del','der','di','la','le','van','der','den','vel','von');
// name parts that should be lower even if at the beginning of a name
$always_lower = array('van', 'der');
// Create an array from the parts of the string passed in
$parts = explode(" ", mb_strtolower($str));
foreach ($parts as $part)
{
(in_array($part, $ok_to_be_lower)) ? $rules[$part] = 'nocaps' : $rules[$part] = 'caps';
}
// Determine the first part in the string
reset($rules);
$first_part = key($rules);
// Loop through and cap-or-dont-cap
foreach ($rules as $part => $rule)
{
if ($rule == 'caps')
{
// ucfirst() words and also takes into account apostrophes and hyphens like this:
// O'brien -> O'Brien || mary-kaye -> Mary-Kaye
$part = str_replace('- ','-',ucwords(str_replace('-','- ', $part)));
$c13n[] = str_replace('\' ', '\'', ucwords(str_replace('\'', '\' ', $part)));
}
else if ($part == $first_part && !in_array($part, $always_lower))
{
// If the first part of the string is ok_to_be_lower, cap it anyway
$c13n[] = ucfirst($part);
}
else
{
$c13n[] = $part;
}
}
$titleized = implode(' ', $c13n);
return trim($titleized);
}
J'ai fait une rapide C# port de https://github.com/tamtamchik/namecase, qui est basé sur la Lingua::FR::NameCase.
public static class CIQNameCase
{
static Dictionary<string, string> _exceptions = new Dictionary<string, string>
{
{@"\bMacEdo" ,"Macedo"},
{@"\bMacEvicius" ,"Macevicius"},
{@"\bMacHado" ,"Machado"},
{@"\bMacHar" ,"Machar"},
{@"\bMacHin" ,"Machin"},
{@"\bMacHlin" ,"Machlin"},
{@"\bMacIas" ,"Macias"},
{@"\bMacIulis" ,"Maciulis"},
{@"\bMacKie" ,"Mackie"},
{@"\bMacKle" ,"Mackle"},
{@"\bMacKlin" ,"Macklin"},
{@"\bMacKmin" ,"Mackmin"},
{@"\bMacQuarie" ,"Macquarie"}
};
static Dictionary<string, string> _replacements = new Dictionary<string, string>
{
{@"\bAl(?=\s+\w)" , @"al"}, // al Arabic or forename Al.
{@"\b(Bin|Binti|Binte)\b" , @"bin"}, // bin, binti, binte Arabic
{@"\bAp\b" , @"ap"}, // ap Welsh.
{@"\bBen(?=\s+\w)" , @"ben"}, // ben Hebrew or forename Ben.
{@"\bDell([ae])\b" , @"dell$1"}, // della and delle Italian.
{@"\bD([aeiou])\b" , @"d$1"}, // da, de, di Italian; du French; do Brasil
{@"\bD([ao]s)\b" , @"d$1"}, // das, dos Brasileiros
{@"\bDe([lrn])\b" , @"de$1"}, // del Italian; der/den Dutch/Flemish.
{@"\bEl\b" , @"el"}, // el Greek or El Spanish.
{@"\bLa\b" , @"la"}, // la French or La Spanish.
{@"\bL([eo])\b" , @"l$1"}, // lo Italian; le French.
{@"\bVan(?=\s+\w)" , @"van"}, // van German or forename Van.
{@"\bVon\b" , @"von"} // von Dutch/Flemish
};
static string[] _conjunctions = { "Y", "E", "I" };
static string _romanRegex = @"\b((?:[Xx]{1,3}|[Xx][Ll]|[Ll][Xx]{0,3})?(?:[Ii]{1,3}|[Ii][VvXx]|[Vv][Ii]{0,3})?)\b";
/// <summary>
/// Case a name field into its appropriate case format
/// e.g. Smith, de la Cruz, Mary-Jane, O'Brien, McTaggart
/// </summary>
/// <param name="nameString"></param>
/// <returns></returns>
public static string NameCase(string nameString)
{
// Capitalize
nameString = Capitalize(nameString);
nameString = UpdateIrish(nameString);
// Fixes for "son (daughter) of" etc
foreach (var replacement in _replacements.Keys)
{
if (Regex.IsMatch(nameString, replacement))
{
Regex rgx = new Regex(replacement);
nameString = rgx.Replace(nameString, _replacements[replacement]);
}
}
nameString = UpdateRoman(nameString);
nameString = FixConjunction(nameString);
return nameString;
}
/// <summary>
/// Capitalize first letters.
/// </summary>
/// <param name="nameString"></param>
/// <returns></returns>
private static string Capitalize(string nameString)
{
nameString = nameString.ToLower();
nameString = Regex.Replace(nameString, @"\b\w", x => x.ToString().ToUpper());
nameString = Regex.Replace(nameString, @"'\w\b", x => x.ToString().ToLower()); // Lowercase 's
return nameString;
}
/// <summary>
/// Update for Irish names.
/// </summary>
/// <param name="nameString"></param>
/// <returns></returns>
private static string UpdateIrish(string nameString)
{
if(Regex.IsMatch(nameString, @".*?\bMac[A-Za-z^aciozj]{2,}\b") || Regex.IsMatch(nameString, @".*?\bMc"))
{
nameString = UpdateMac(nameString);
}
return nameString;
}
/// <summary>
/// Updates irish Mac & Mc.
/// </summary>
/// <param name="nameString"></param>
/// <returns></returns>
private static string UpdateMac(string nameString)
{
MatchCollection matches = Regex.Matches(nameString, @"\b(Ma?c)([A-Za-z]+)");
if(matches.Count == 1 && matches[0].Groups.Count == 3)
{
string replacement = matches[0].Groups[1].Value;
replacement += matches[0].Groups[2].Value.Substring(0, 1).ToUpper();
replacement += matches[0].Groups[2].Value.Substring(1);
nameString = nameString.Replace(matches[0].Groups[0].Value, replacement);
// Now fix "Mac" exceptions
foreach (var exception in _exceptions.Keys)
{
nameString = Regex.Replace(nameString, exception, _exceptions[exception]);
}
}
return nameString;
}
/// <summary>
/// Fix roman numeral names.
/// </summary>
/// <param name="nameString"></param>
/// <returns></returns>
private static string UpdateRoman(string nameString)
{
MatchCollection matches = Regex.Matches(nameString, _romanRegex);
if (matches.Count > 1)
{
foreach(Match match in matches)
{
if(!string.IsNullOrEmpty(match.Value))
{
nameString = Regex.Replace(nameString, match.Value, x => x.ToString().ToUpper());
}
}
}
return nameString;
}
/// <summary>
/// Fix Spanish conjunctions.
/// </summary>
/// <param name=""></param>
/// <returns></returns>
private static string FixConjunction(string nameString)
{
foreach (var conjunction in _conjunctions)
{
nameString = Regex.Replace(nameString, @"\b" + conjunction + @"\b", x => x.ToString().ToLower());
}
return nameString;
}
}
L'utilisation de la
string name_cased = CIQNameCase.NameCase("McCarthy");
C'est ma méthode de test, tout semble se passer OK:
[TestMethod]
public void Test_NameCase_1()
{
string[] names = {
"Keith", "Yuri's", "Leigh-Williams", "McCarthy",
// Mac exceptions
"Machin", "Machlin", "Machar",
"Mackle", "Macklin", "Mackie",
"Macquarie", "Machado", "Macevicius",
"Maciulis", "Macias", "MacMurdo",
// General
"O'Callaghan", "St. John", "von Streit",
"van Dyke", "Van", "ap Llwyd Dafydd",
"al Fahd", "Al",
"el Grecco",
"ben Gurion", "Ben",
"da Vinci",
"di Caprio", "du Pont", "de Legate",
"del Crond", "der Sind", "van der Post", "van den Thillart",
"von Trapp", "la Poisson", "le Figaro",
"Mack Knife", "Dougal MacDonald",
"Ruiz y Picasso", "Dato e Iradier", "Mas i Gavarró",
// Roman numerals
"Henry VIII", "Louis III", "Louis XIV",
"Charles II", "Fred XLIX", "Yusof bin Ishak",
};
foreach(string name in names)
{
string name_upper = name.ToUpper();
string name_cased = CIQNameCase.NameCase(name_upper);
Console.WriteLine(string.Format("name: {0} -> {1} -> {2}", name, name_upper, name_cased));
Assert.IsTrue(name == name_cased);
}
}
Quel langage utilisez-vous?De nombreux langages permettent des fonctions de rappel pour l'expression régulière correspond.Ceux-ci peuvent être utilisés pour propercase le match facilement.L'expression régulière qui doit être utilisée est assez simple, il vous suffit de faire correspondre tous les caractères de mot, comme ceci:
/\w+/
Alternativement, vous pouvez déjà extrait du premier caractère à un supplément de match:
/(\w)(\w*)/
Maintenant, vous pouvez accéder à la première de caractères et des caractères successifs dans le match séparément.La fonction de rappel peut ensuite il suffit de retourner une concaténation de la frappe.Dans le pseudo Python (je ne connais pas Python):
def make_proper(match):
return match[1].to_upper + match[2]
D'ailleurs, cela permettrait également de traiter le cas des “O'Reilly”, parce que “O” et “Reilly” serait payée séparément et les deux propercased.Il existe cependant d'autres cas spéciaux qui ne sont pas gérées par l'algorithme, par exemple“Mcdonald's” ou plus généralement tout apostrophed mot.L'algorithme pourrait produire “Mcdonald'S” pour le second.Un traitement spécial pour l'apostrophe peut être mis en œuvre, mais qui pourrait interférer avec le premier cas.Trouver un thereotical solution parfaite n'est pas possible.Dans la pratique, il peut être utile compte tenu de la longueur de la partie après l'apostrophe.
Voici peut-être naïf C# de mise en œuvre:-
public class ProperCaseHelper {
public string ToProperCase(string input) {
string ret = string.Empty;
var words = input.Split(' ');
for (int i = 0; i < words.Length; ++i) {
ret += wordToProperCase(words[i]);
if (i < words.Length - 1) ret += " ";
}
return ret;
}
private string wordToProperCase(string word) {
if (string.IsNullOrEmpty(word)) return word;
// Standard case
string ret = capitaliseFirstLetter(word);
// Special cases:
ret = properSuffix(ret, "'");
ret = properSuffix(ret, ".");
ret = properSuffix(ret, "Mc");
ret = properSuffix(ret, "Mac");
return ret;
}
private string properSuffix(string word, string prefix) {
if(string.IsNullOrEmpty(word)) return word;
string lowerWord = word.ToLower(), lowerPrefix = prefix.ToLower();
if (!lowerWord.Contains(lowerPrefix)) return word;
int index = lowerWord.IndexOf(lowerPrefix);
// If the search string is at the end of the word ignore.
if (index + prefix.Length == word.Length) return word;
return word.Substring(0, index) + prefix +
capitaliseFirstLetter(word.Substring(index + prefix.Length));
}
private string capitaliseFirstLetter(string word) {
return char.ToUpper(word[0]) + word.Substring(1).ToLower();
}
}
un moyen simple pour mettre en majuscule la première lettre de chaque mot (séparés par un espace)
$words = explode(” “, $string);
for ($i=0; $i<count($words); $i++) {
$s = strtolower($words[$i]);
$s = substr_replace($s, strtoupper(substr($s, 0, 1)), 0, 1);
$result .= “$s “;
}
$string = trim($result);
en termes d'attraper le "O'REILLY" exemple que vous avez donné le fractionnement de la chaîne sur les deux espaces et " ne fonctionnerait pas comme il le ferait tirer parti de toute lettre qui a paru après une apostraphe c'est à direle s dans de Fred
donc, je serais probablement essayer quelque chose comme
$words = explode(” “, $string);
for ($i=0; $i<count($words); $i++) {
$s = strtolower($words[$i]);
if (substr($s, 0, 2) === "o'"){
$s = substr_replace($s, strtoupper(substr($s, 0, 3)), 0, 3);
}else{
$s = substr_replace($s, strtoupper(substr($s, 0, 1)), 0, 1);
}
$result .= “$s “;
}
$string = trim($result);
Ceci devrait attraper O'Reilly, Heures, O'Donnell, etc j'espère que ça aide
Veuillez noter que ce code n'est pas testé.
Kronoz, je vous remercie.J'ai trouvé dans votre fonction que la ligne:
`if (!lowerWord.Contains(lowerPrefix)) return word`;
faut dire
if (!lowerWord.StartsWith(lowerPrefix)) return word;
donc "información" n'est pas changé à "InforMacIón"
mieux,
Enrique
J'utilise ce que l'événement textchanged gestionnaire de zones de texte.Soutien à l'intégration de "Mcdonald's"
Public Shared Function DoProperCaseConvert(ByVal str As String, Optional ByVal allowCapital As Boolean = True) As String
Dim strCon As String = ""
Dim wordbreak As String = " ,.1234567890;/\-()#$%^&*€!~+=@"
Dim nextShouldBeCapital As Boolean = True
'Improve to recognize all caps input
'If str.Equals(str.ToUpper) Then
' str = str.ToLower
'End If
For Each s As Char In str.ToCharArray
If allowCapital Then
strCon = strCon & If(nextShouldBeCapital, s.ToString.ToUpper, s)
Else
strCon = strCon & If(nextShouldBeCapital, s.ToString.ToUpper, s.ToLower)
End If
If wordbreak.Contains(s.ToString) Then
nextShouldBeCapital = True
Else
nextShouldBeCapital = False
End If
Next
Return strCon
End Function
Beaucoup de bonnes réponses ici.Le mien est assez simple et ne prend en compte que les noms que nous avons dans notre organisation.Vous pouvez l'agrandir comme vous le souhaitez.Ce n'est pas une solution parfaite et va changer de vancouver à vancouver, ce qui est faux.Afin de l'ajuster si vous l'utilisez.
C'était ma solution en C#.Ce hard-codes les noms dans le programme, mais avec un peu de travail, vous pouvez garder un fichier texte à l'extérieur du programme et de lire le nom des exceptions (c'est à direVan, Mc, Mac) et de la boucle à travers eux.
public static String toProperName(String name)
{
if (name != null)
{
if (name.Length >= 2 && name.ToLower().Substring(0, 2) == "mc") // Changes mcdonald to "McDonald"
return "Mc" + Regex.Replace(name.ToLower().Substring(2), @"\b[a-z]", m => m.Value.ToUpper());
if (name.Length >= 3 && name.ToLower().Substring(0, 3) == "van") // Changes vanwinkle to "VanWinkle"
return "Van" + Regex.Replace(name.ToLower().Substring(3), @"\b[a-z]", m => m.Value.ToUpper());
return Regex.Replace(name.ToLower(), @"\b[a-z]", m => m.Value.ToUpper()); // Changes to title case but also fixes
// appostrophes like O'HARE or o'hare to O'Hare
}
return "";
}
Je sais que ce fil a été ouvert pendant un certain temps, mais comme je faisais des recherches pour ce problème, je suis tombé sur ce chouette site, qui vous permet de coller des noms en majuscule assez rapidement: https://dialect.ca/code/name-case/.Je voulais l'inclure ici à titre de référence pour les personnes effectuant des recherches similaires/projets.
Ils se libèrent de l'algorithme qu'ils ont écrit en php sur ce lien: https://dialect.ca/code/name-case/name_case.phps
Un test préliminaire et de la lecture de leur code suggère qu'ils ont été assez approfondi.
Vous ne mentionnez pas la langue dans laquelle vous souhaitez la solution en voici donc quelques pseudo-code.
Loop through each character
If the previous character was an alphabet letter
Make the character lower case
Otherwise
Make the character upper case
End loop