2009-07-08 13 views
25

estoy usando la expresión regularExpresión regular, cuerda dividida por la letra mayúscula, pero ignoran TLA

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

para dividir cadenas de letra mayúscula, por ejemplo:

'MyNameIsSimon' convierte 'Mi Nombre es Simon '

Esto me resulta increíblemente útil cuando trabajo con enumeraciones. Lo que me gustaría hacer es cambiar un poco para que las cuerdas solamente se dividen si el siguiente carta es una letra minúscula, por ejemplo:

'USA Today' se convertiría en 'EE.UU. Hoy'

¿Se puede hacer esto?

EDITAR: Gracias a todos por su respuesta. Puede que no haya pensado completamente en esto, en algunos casos 'A' y 'I' tendrían que ser ignorados, pero esto no es posible (al menos no de una manera significativa). En mi caso, las respuestas a continuación hacen lo que necesito. ¡Gracias!

+1

Hmmm ... esto podría no ser tan simple como se pensó inicialmente, ¿qué tal una cadena como "TodayILiveInTheUSAWithSimon"? Ambas respuestas actuales no serán suficientes. –

+0

Buen punto. Sin embargo, puedo trabajar en eso en esta instancia. – Simon

Respuesta

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

o su primo compatibles con Unicode

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

cuando reemplazó a nivel mundial con

" $1" 

maneja

 
TodayILiveInTheUSAWithSimon 
USAToday 
IAmSOOOBored 

rendimiento

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

En un segundo paso, tendría que recortar la cuerda.

+0

¡Lo siento, me has perdido un poco! De esta manera: Reemplazar (stringToSplit, "([A-Z]) (? = [A-z]) | (? <= [A-z]) ([A-Z])", "\ 1")? – Simon

+0

El '\ 1' significa referencia # 1. En las expresiones regulares de .NET, esto se expresa como '$ 1'. Aparte de eso, su declaración parece correcta. – Tomalak

+0

He editado la respuesta, por lo que utiliza la referencia posterior de estilo .NET. – Tomalak

11

cualquier carácter en mayúscula que no vaya seguida de un carácter en mayúscula:

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

Editar:

Acabo de notar que usted está usando esto para enumeraciones. Realmente no aliento el uso de representaciones de cadenas de enumeraciones como esta, y los problemas a mano son una buena razón por qué. Eche un vistazo a esto en su lugar: http://www.refactoring.com/catalog/replaceTypeCodeWithClass.html

+0

Eso no maneja "I", es decir, "IAmBored" no se dividirá como "Estoy aburrido", como supongo que esperaría el OP. –

+0

Creo que estás equivocado. prueba este javascript por ti mismo: alerta ("IAmBored" .replace (/ ([A-Z]) (?! [A-Z])/g, "$ 1")); coincidirá con "A" y "B" ya que ambos no son seguidos por un carácter en mayúscula y se reemplazan en "A" y "B" respectivamente –

+0

(aunque me acabo de dar cuenta de que está equivocado con su elección ejemplo, el punto general sigue siendo exacto, cuando la "I" está en el medio de una oración) –

1

Puede pensar en cambiar las enumeraciones; Las pautas de codificación de MS sugieren acrónimos de cassette Pascal como si fueran palabras; XmlDocument, HtmlWriter, etc. Los acrónimos de dos letras no siguen esta regla; System.IO.

Entonces debería usar UsaToday, y su problema desaparecerá.

+0

Aunque estoy totalmente contigo en general, esto realmente no resuelve el problema. Si hubiera escrito UsaToday, esto daría lugar a la secuencia dividida (es decir, legible para los humanos) como "Usa Today", lo cual es un tanto extraño, ya que siempre está escrita en los Estados Unidos. Por lo tanto, puedo entender el deseo de conservar las mayúsculas. Por otro lado, si uno quisiera mostrar nombres enum a los usuarios, uno debería ir con otra solución (tiendo a tener recursos de cadenas como EnumName_ValueName, por lo que la clave se puede generar fácilmente en código, se puede buscar en el archivo de recursos y puede fácilmente localizado). – OregonGhost

0

La expresión de Tomalak funcionó para mí, pero no con la función incorporada Replace. Regex.Replace(), sin embargo, funcionó.

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 

Por cierto, estoy usando esto para dividir las palabras en los nombres de enumeración para su visualización en la interfaz de usuario y funciona muy bien.

0

Nota: No leí la pregunta lo suficientemente bien, USAToday me devolverá "Hoy"; por lo que este awser no es el correcto.

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

Esto corresponderá con "WakeOnBoot" como "Wake On Boot" y no devuelve nada en NMI o TLA

0

Mi versión que también se ocupa de las expresiones aritméticas 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 Espero que esto lo ayude a dividir una cadena por sus letras mayúsculas y mucho más. Puede intentar usar Humanizer, que es un paquete nuget gratuito. Esto le ahorrará más problemas con letras, oraciones, números, cantidades y mucho más en muchos idiomas. Echa un vistazo a esto en: https://www.nuget.org/packages/Humanizer/

+0

¡útil, gracias! – Simon

Cuestiones relacionadas