2009-07-08 7 views
25

J'utilise l'expression rationnelleExpression régulière, Éclate une chaîne par lettre majuscule, mais ignorer TLA

System.Text.RegularExpressions.Regex.Replace(stringToSplit, "([A-Z])", " $1").Trim() 

pour diviser les chaînes par lettre majuscule, par exemple:

« MyNameIsSimon » devient « Mon Le nom est Simon '

Je trouve cela incroyablement utile lorsque vous travaillez avec des énumérations. Ce que je voudrais faire est de changer légèrement pour que les chaînes ne sont séparés si le suivant lettre est une lettre minuscule, par exemple:

« USAToday » deviendrait « USA Today »

Est-ce que cela peut être fait?

EDIT: Merci à tous pour votre réponse. Je n'ai peut-être pas entièrement réfléchi à cela, dans certains cas, «A» et «I» auraient besoin d'être ignorés, mais ce n'est pas possible (du moins pas de manière significative). Dans mon cas, les réponses ci-dessous font ce dont j'ai besoin. Merci!

+1

Hmmm ... ce n'est peut-être pas aussi simple qu'on le pensait au début - que diriez-vous d'une chaîne comme "TodayILiveInTheUSAWithSimon" - les deux réponses actuelles échoueront pour cela. –

+0

Bon point. Je peux probablement contourner cela dans ce cas. – Simon

Répondre

39
 
((?<=[a-z])[A-Z]|[A-Z](?=[a-z])) 

ou son cousin Unicode conscient

 
((?<=\p{Ll})\p{Lu}|\p{Lu}(?=\p{Ll})) 

lors de son remplacement à l'échelle mondiale avec

" $1" 

poignées

 
TodayILiveInTheUSAWithSimon 
USAToday 
IAmSOOOBored 

rendement

 
Today I Live In The USA With Simon 
USA Today 
I Am SOOO Bored 

Dans une seconde étape, vous devez couper la chaîne.

+0

Désolé, vous m'avez perdu un peu! Comme ceci: Replace (stringToSplit, "([A-Z]) (? = [A-z]) | (? <= [A-z]) ([A-Z])", "\ 1")? – Simon

+0

Le '\ 1' signifie la référence arrière # 1. Dans les expressions rationnelles .NET, ceci est exprimé en $ 1. À part cela, votre déclaration semble correcte. – Tomalak

+0

J'ai modifié la réponse pour qu'elle utilise la référence arrière de style .NET. – Tomalak

11

tout caractère majuscule qui ne sont pas suivi par un caractère majuscule:

Replace(string, "([A-Z])(?![A-Z])", " $1") 

Edit:

Je viens de remarquer que vous utilisez cela pour énumérations. Je n'encourage pas vraiment à utiliser des représentations sous forme de chaîne d'énumérations comme celle-ci, et les problèmes à résoudre sont une bonne raison pour cela. Jetez un oeil à cela à la place: http://www.refactoring.com/catalog/replaceTypeCodeWithClass.html

+0

Cela ne gère pas "I", c'est-à-dire que "IAmBored" ne sera pas scindé en "I Am Bored" comme je suppose que le OP s'attendrait. –

+0

Je pense que vous vous trompez. essayez ce javascript pour vous-même: alert ("IAmBored" .replace (/ ([A-Z]) (?! [A-Z])/g, "$ 1")); il correspondra "A" et "B" car les deux ne sont pas suivis d'une majuscule, et être remplacés par "A" et "B" respectivement –

+0

(bien que je viens de réaliser que vous vous trompez avec votre choix de Par exemple, le point général est toujours précis, car lorsque le "je" est au milieu d'une phrase) –

1

Vous pourriez penser à changer les énumérations; Les directives de codage MS suggèrent que Pascal utilise des acronymes comme s'il s'agissait de mots; XmlDocument, HtmlWriter, etc. Les acronymes à deux lettres ne suivent pas cette règle, cependant; System.IO.

Vous devriez donc utiliser UsaToday, et votre problème disparaîtra.

+0

Alors que je suis totalement avec vous en général, cela ne résout pas vraiment le problème. S'il avait écrit UsaToday, cela se traduirait par la chaîne divisée (c'est-à-dire lisible par l'homme) comme "Usa Today", ce qui est assez étrange car il est toujours écrit aux USA. Par conséquent, je peux comprendre le désir de conserver la capitalisation. D'un autre côté, si l'on voulait montrer les noms des utilisateurs, on devrait utiliser une autre solution (j'ai tendance à avoir des ressources comme EnumName_ValueName, donc la clé peut être facilement générée en code, consultable dans le fichier ressource et peut être facilement localisé). – OregonGhost

0

L'expression de Tomalak a fonctionné pour moi, mais pas avec la fonction Replace intégrée. Regex.Replace(), cependant, a travaillé.

For i As Integer = 0 To names.Length - 1 
    'Worked 
    names(i) = Regex.Replace(names(i), "((?<=[a-z])[A-Z]|[A-Z](?=[a-z]))", " $1").TrimStart() 

    ' Didn't work 
    'names(i) = Replace(names(i), "([A-Z])(?=[a-z])|(?<=[a-z])([A-Z])", " $1").TrimStart() 
Next 

BTW, j'utilise ceci pour séparer les mots dans les noms d'énumération pour l'affichage dans l'interface utilisateur et il fonctionne à merveille.

0

Note: Je n'ai pas assez lu la question, USAToday retournera "Today"; donc cette réponse n'est pas la bonne.

public static List<string> SplitOnCamelCase(string text) 
    { 
     List<string> list = new List<string>(); 
     Regex regex = new Regex(@"(\p{Lu}\p{Ll}+)"); 
     foreach (Match match in regex.Matches(text)) 
     { 
      list.Add (match.Value); 
     } 
     return list; 
    } 

Cela correspondra "WakeOnBoot" comme "Wake On Boot" et ne retourne rien sur NMI ou TLA

0

Ma version qui gère également les expressions arithmétiques simples:

private string InjectSpaces(string s) 
{ 
    var patterns = new string[] { 
     @"(?<=[^A-Z,&])[A-Z]",   // match capital preceded by any non-capital except ampersand 
     @"(?<=[A-Z])[A-Z](?=[a-z])", // match capital preceded by capital and followed by lowercase letter 
     @"[\+\-\*\/\=]",    // match arithmetic operators 
     @"(?<=[\+\-\*\/\=])[0-9,\(]" // match 0-9 or open paren preceded by arithmetic operator 
    }; 
    var pattern = $"({string.Join("|", patterns)})"; 
    return Regex.Replace(s, pattern, " $1"); 
} 
1

I J'espère que cela vous aidera à diviser une chaîne par ses majuscules et bien plus encore. Vous pouvez essayer d'utiliser Humanizer, qui est un paquet de nuget gratuit. Cela vous épargnera plus de problèmes avec des lettres, des phrases, des chiffres, des quantités et beaucoup plus dans de nombreuses langues. Check out this at: https://www.nuget.org/packages/Humanizer/

+0

utile, merci! – Simon

Questions connexes