2009-07-08 16 views
25

sto usando l'espressione regolareespressioni regolari, stringa divisa dalla lettera maiuscola, ma ignorare TLA

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

per dividere le stringhe di lettera maiuscola, ad esempio:

'MyNameIsSimon' diventa 'My Nome Is Simon '

Trovo che questo sia incredibilmente utile quando si lavora con le enumerazioni. Quello che vorrei fare è cambiare leggermente in modo che le stringhe sono divisi solo se il prossimo lettera è una lettera minuscola, per esempio:

'USAToday' sarebbe diventato 'USA Today'

Questo può essere fatto?

EDIT: Grazie a tutti per aver risposto. Potrei non averlo pensato interamente, in alcuni casi 'A' e 'I' avrebbero dovuto essere ignorati ma questo non è possibile (almeno non in modo significativo). Nel mio caso però le risposte di seguito fanno quello di cui ho bisogno. Grazie!

+1

Hmmm ... questo potrebbe non essere così semplice come inizialmente pensato - che dire di una stringa come "TodayILiveInTheUSAWithSimon" - entrambe le risposte attuali non riuscire per questo. –

+0

Buon punto. Probabilmente posso aggirare il problema anche se in questo caso. – Simon

risposta

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

o suo cugino Unicode consapevoli

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

quando sostituite globalmente con

" $1" 

maniglie

 
TodayILiveInTheUSAWithSimon 
USAToday 
IAmSOOOBored 

cedevole

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

In una seconda fase è necessario tagliare la stringa.

+0

Scusa, mi hai perso un po '! In questo modo: Replace (stringToSplit, "([A-Z]) (? = [A-z]) | (? <= [A-z]) ([A-Z])", "\ 1")? – Simon

+0

Il '\ 1' significa back-reference # 1. In regex .NET, questo è espresso come '$ 1'. A parte questo, la tua affermazione sembra corretta. – Tomalak

+0

Ho modificato la risposta in modo che utilizzi il back-reference in stile .NET. – Tomalak

11

qualsiasi carattere maiuscolo che non è seguito da un carattere maiuscolo:

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

Edit:

Ho appena notato che si sta utilizzando questo per enumerazioni. Io davvero non incoraggio l'uso di rappresentazioni di stringa di enumerazioni come questa, e i problemi a portata di mano sono una buona ragione per cui. Date un'occhiata a questo: http://www.refactoring.com/catalog/replaceTypeCodeWithClass.html

+0

Questo non gestisce "I", cioè "IAmBored" non sarà diviso come "I Am Bored" come presumo che l'OP si aspetterebbe. –

+0

penso che ti sbagli. prova questo javascript per te: avviso ("IAmBored" .replace (/ ([A-Z]) (?! [A-Z])/g, "$ 1")); corrisponderà a "A" e "B" in quanto entrambi non sono seguiti da un carattere maiuscolo, e saranno sostituiti in "A" e "B" rispettivamente –

+0

(anche se ho appena capito che ti stai solo sbagliando Ad esempio, il punto generale è ancora preciso, poiché quando "I" è nel mezzo di una frase) –

1

Si potrebbe pensare di cambiare le enumerazioni; Le linee guida sulla codifica MS suggeriscono gli acronimi del rivestimento Pascal come se fossero parole; XmlDocument, HtmlWriter, ecc. Gli acryonimi di due lettere non seguono questa regola; System.IO.

Quindi dovresti utilizzare UsaToday e il tuo problema scomparirà.

+0

Mentre sono totalmente con te in generale, questo non risolve il problema. Se avesse scritto UsaToday, questo risulterebbe nella stringa divisa (cioè leggibile dall'uomo) come "Usa Today", che è piuttosto strana dato che è sempre stata scritta negli Stati Uniti. Quindi posso capire il desiderio di mantenere la capitalizzazione. D'altra parte, se si volesse mostrare i nomi enum agli utenti, si dovrebbe andare con un'altra soluzione (io tendo ad avere risorse di stringa come EnumName_ValueName, quindi la chiave può essere facilmente generata nel codice, è ricercabile nel file di risorse e può essere facilmente localizzato). – OregonGhost

0

L'espressione di Tomalak ha funzionato per me, ma non con la funzione integrata Replace. Regex.Replace(), tuttavia, ha funzionato.

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, sto usando questo per dividere le parole nomi di enumerazione per la visualizzazione nell'interfaccia utente e funziona meravigliosamente.

0

Nota: non ho letto abbastanza bene la domanda, USAToday tornerà "Oggi"; quindi questo anwser non è quello giusto.

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; 
    } 

Questa corrisponderà "WakeOnBoot" come "Wake On Boot" e non restituisce nulla sul NMI o TLA

0

La mia versione che gestisce anche semplici espressioni aritmetiche:

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 spero che questo ti aiuterà a spaccare una stringa con le sue lettere maiuscole e molto altro ancora. Puoi provare a utilizzare Humanizer, che è un pacchetto gratuito di nuget. Ciò ti farà risparmiare ulteriori problemi con lettere, frasi, numeri, quantità e molto altro in molte lingue. Dai un'occhiata a questo in: https://www.nuget.org/packages/Humanizer/

+0

utile, grazie! – Simon

Problemi correlati