2015-06-05 6 views
8

Voglio dividere le parole camelCase o PascalCase nello spazio separato di parole.Ignora gli spazi esistenti nella conversione di CamelCase alla stringa con spazi

Finora, ho:

Regex.Replace(value, @"(\B[A-Z]+?(?=[A-Z][^A-Z])|\B[A-Z]+?(?=[^A-Z]))", " $0", RegexOptions.Compiled); 

Funziona bene per la conversione "TESTWORD" a "prova di parola" e per lasciare intatta singole parole, per esempio Testing rimane Testing.

Tuttavia, ABCTest viene convertito in A B C Test quando preferirei ABC Test.

risposta

4

Prova:

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

An example on Regex101


come viene utilizzato in CS?

string strText = " TestWord asdfDasdf ABCDef"; 

string[] matches = Regex.Matches(strText, @"[A-Z][a-z]+|[A-Z]+(?=[A-Z][a-z])|[a-z]+|[A-Z]+") 
       .Cast<Match>() 
       .Select(m => m.Value) 
       .ToArray(); 

string result = String.Join(" ", matches); 

result = 'Test Word asdf Dasdf ABC Def'


Come funziona

Nella stringa di esempio:

TestWord qwerDasdf 
ABCTest Testing ((*&^%$CamelCase!"£$%^^)) 
asdfAasdf 
AaBbbCD 

[A-Z][a-z]+ incontri:

  • [0-4] Test
  • [4-8] Word
  • [13-18] Dasdf
  • [22-26] Test
  • [27-34] Testing
  • [45 -50] Camel
  • [50-54] Case
  • [68-73] Aasdf
  • 01.235.
  • [74-76] Aa
  • [76-79] Bbb

[A-Z]+(?=[A-Z][a-z]) incontri:

  • [19-22] ABC

[a-z]+ partite:

  • [9-13] qwer
  • [64-68] asdf

[A-Z]+ incontri:

  • [79-81] CD
+0

Grazie per la tua risposta ma non funziona quando il valore ha già uno spazio. Finisce per raddoppiare lo spazio, ad esempio "Test ABC" diventa "Test ABC" Ugualmente "ABCTest" diventa "Test ABC", cioè lo spazio principale viene mantenuto. –

+1

@CiaranMartin Vorrei usare 'Regex.match()' per ottenere un 'MatchCollection' di tutte le partite elencate sopra. È quindi possibile eseguire il cast su un array e unirlo in una stringa utilizzando un singolo separatore di spazi. Ciò mantiene molta della logica fuori dalla tua regex e rende il codice più leggibile. – thodic

+0

@CiaranMartin vedere la mia modifica per l'implementazione C#. – thodic

1

Qui è il mio tentativo:

(?<!^|\b|\p{Lu})\p{Lu}+(?=\p{Ll}|\b)|(?<!^\p{Lu}*|\b)\p{Lu}(?=\p{Ll}|(?<!\p{Lu}*)\b) 

Questa espressione regolare può essere utilizzata con Regex.Replace e $0 come stringa sostitutiva.

Regex.Replace(value, @"(?<!^|\b|\p{Lu})\p{Lu}+(?=\p{Ll}|\b)|(?<!^\p{Lu}*|\b)\p{Lu}(?=\p{Ll}|(?<!\p{Lu}*)\b)", " $0", RegexOptions.Compiled); 

Vedi demo

Regex Spiegazione:

  • Contiene 2 alternative per tenere conto di una catena di lettere maiuscole, prima o dopo le lettere minuscole.
  • (?<!^|\b|\p{Lu})\p{Lu}+(?=\p{Ll}|\b) - prima alternativa che soddisfa alcune lettere maiuscole, che non sono preceduti da un inizio di corda, limite di una parola o di un'altra lettera maiuscola, e che sono seguiti da una lettera minuscola o un confine di parola,
  • (?<!^\p{Lu}*|\b)\p{Lu}(?=\p{Ll}|(?<!\p{Lu}*)\b) - la seconda alternativa che corrisponde a una singola lettera maiuscola che non è preceduta da un inizio di stringa con lettere maiuscole facoltative subito dopo, o un limite di parola ed è seguita da una lettera minuscola o un limite di parola che non è preceduto da lettere maiuscole facoltative.
+0

Hai avuto tempo di controllare il mio approccio? –

+0

L'ho fatto, ma RegEx è abbastanza difficile senza dover decifrare la sintassi \ p {Lu}. L'ho provato e non ha funzionato correttamente per "ABC Test" poiché emette "AB C Test" quando mi aspetto "Test ABC" –

+0

Non è così, dai un'occhiata più da vicino alla scheda Contesto su Demo RegexStorm . Mostra 'ABC Test'. '\ p {Lu}' è una lettera maiuscola, '\ p {Ll}' è una lettera minuscola e * questo supporta Unicode *. Funzionerà con il russo o il polacco e altri script con maiuscole/minuscole. –

0

È necessario utilizzare Regex? Ad essere onesti, non userei il Regex per questo. Sono difficili da eseguire il debug e non sono particolarmente leggibili.

vorrei andare con una piccola, riutilizzabile, metodo di estensione facilmente verificabile:

class Program 
{ 
    static void Main(string[] args) 
    { 
     string[] inputs = new[] 
     { 
      "ABCTest", 
      "HelloWorld", 
      "testTest$Test", 
      "aaҚbb" 
     }; 

     var output = inputs.Select(x => x.SplitWithSpaces(CultureInfo.CurrentUICulture)); 

     foreach (string x in output) 
     { 
      Console.WriteLine(x); 
     } 

     Console.Read(); 
    } 
} 

public static class StringExtensions 
{ 
    public static bool IsLowerCase(this TextInfo textInfo, char input) 
    { 
     return textInfo.ToLower(input) == input; 
    } 

    public static string SplitWithSpaces(this string input, CultureInfo culture = null) 
    { 
     if (culture == null) 
     { 
      culture = CultureInfo.InvariantCulture; 
     } 
     TextInfo textInfo = culture.TextInfo; 

     StringBuilder sb = new StringBuilder(input); 

     for (int i = 1; i < sb.Length; i++) 
     { 
      int previous = i - 1; 

      if (textInfo.IsLowerCase(sb[previous])) 
      { 
       int insertLocation = previous - 1; 

       if (insertLocation > 0) 
       { 
        sb.Insert(insertLocation, ' '); 
       } 

       while (i < sb.Length && textInfo.IsLowerCase(sb[i])) 
       { 
        i++; 
       } 
      }     
     } 

     return sb.ToString(); 
    } 
} 
+0

Grazie per la tua risposta, ma non ho bisogno di gestire le differenze culturali e sentire la risposta di OhAuth è più semplice e più concisa, anche se ha un'espressione regolare che non è la più facile da capire nel migliore dei casi! –