Dada la cadena "ThisStringHasNoSpacesButItDoesHaveCapitals", cuál es la mejor manera de agregar espacios antes de las letras mayúsculas. Entonces, la cadena final sería "Esta cadena no tiene espacios pero tiene mayúsculas"
Aquí está mi intento con un RegEx
System.Text.RegularExpressions.Regex.Replace(value, "[A-Z]", " $0")
Respuestas:
Las expresiones regulares funcionarán bien (incluso voté por la respuesta de Martin Browns), pero son caras (y personalmente encuentro cualquier patrón más largo que un par de caracteres prohibitivamente obtusos)
Esta función
Lo hará 100,000 veces en 2,968,750 ticks, la expresión regular tomará 25,000,000 ticks (y eso es con la expresión regular compilada).
Es mejor, para un valor dado de mejor (es decir, más rápido), sin embargo, es más código para mantener. "Mejor" es a menudo un compromiso de requisitos competitivos.
Espero que esto ayude :)
Actualización
Hace mucho tiempo que no veo esto, y me di cuenta de que los tiempos no se han actualizado desde que cambió el código (solo cambió un poco).
En una cadena con 'Abbbbbbbbb' repetido 100 veces (es decir, 1,000 bytes), una ejecución de 100,000 conversiones toma la función codificada a mano 4,517,177 ticks, y el Regex a continuación toma 59,435,719 haciendo que la función codificada a mano se ejecute en 7.6% del tiempo que toma Regex.
Actualización 2 ¿Tendrá en cuenta las siglas? ¡Lo hará ahora! La lógica de la declaración if es bastante oscura, como puede ver expandiéndola a esto ...
... no ayuda en absoluto!
Aquí está el método simple original que no se preocupa por los acrónimos
fuente
Su solución tiene un problema porque pone un espacio antes de la primera letra T para que obtenga
Para evitar este aspecto, busque también la letra minúscula que lo precede y luego inserte el espacio en el medio:
Editar 1:
Si lo usa
@"(\p{Ll})(\p{Lu})"
, también recogerá caracteres acentuados.Edición 2:
Si sus cadenas pueden contener siglas, puede usar esto:
Entonces, "DriveIsSCSICompatible" se convierte en "Drive Is SCSI Compatible"
fuente
"([^A-Z\\s])([A-Z])"
, incluso con siglas?No probé el rendimiento, pero aquí en una línea con linq:
fuente
Sé que esta es antigua, pero esta es una extensión que uso cuando necesito hacer esto:
Esto te permitirá usar
MyCasedString.ToSentence()
fuente
TrimStart(' ')
, eliminará el espacio inicial.SelectMany
que incluye un índice, de esta manera evita la primera letra y la sobrecarga potencial innecesaria de una llamada adicional aTrimStart(' ')
. Robar.Bienvenido a Unicode
Todas estas soluciones son esencialmente incorrectas para el texto moderno. Necesita usar algo que entienda el caso. Como Bob pidió otros idiomas, le daré un par por Perl.
Proporciono cuatro soluciones, que van de peor a mejor. Solo el mejor siempre tiene la razón. Los otros tienen problemas. Aquí hay una prueba para mostrarle qué funciona y qué no, y dónde. He usado guiones bajos para que pueda ver dónde se han colocado los espacios, y he marcado como incorrecto todo lo que es, bueno, incorrecto.
Por cierto, casi todos aquí han seleccionado la primera forma, la marcada "Peor". Algunos han seleccionado la segunda forma, marcada "OK". Pero nadie más antes que yo te ha mostrado cómo hacer el enfoque "Mejor" o "Mejor".
Aquí está el programa de prueba con sus cuatro métodos:
Cuando pueda obtener el mismo puntaje que el "Mejor" en este conjunto de datos, sabrá que lo ha hecho correctamente. Hasta entonces, no lo has hecho. Nadie más aquí lo ha hecho mejor que "Ok", y la mayoría lo ha hecho "Peor". Espero ver a alguien publicar el código ℂ♯ correcto.
Noté que el código de resaltado de StackOverflow es miserablemente estúpido nuevamente. Están haciendo todo lo mismo cojo que (la mayoría, pero no todos) del resto de los malos enfoques mencionados aquí han hecho. ¿No es hora de dejar de descansar ASCII? Ya no tiene sentido, y pretender que todo lo que tienes es simplemente incorrecto. Es un mal código.
fuente
Me propuse hacer un método de extensión simple basado en el código de Binary Worrier que maneje los acrónimos correctamente y sea repetible (no alterará las palabras ya espaciadas). Aquí está mi resultado.
Aquí están los casos de prueba de unidad que pasa esta función. Agregué la mayoría de los casos sugeridos de tchrist a esta lista. Los tres de los que no pasa (dos son solo números romanos) se comentan:
fuente
Binario Worrier, he usado su código sugerido, y es bastante bueno, solo tengo una pequeña adición:
He agregado una condición
!char.IsUpper(text[i - 1])
. Esto solucionó un error que causaba que algo como 'AverageNOX' se convirtiera en 'Average NO X', lo que obviamente es incorrecto, ya que debería leer 'Average NOX'.Lamentablemente, esto todavía tiene el error de que si tienes el texto 'FromAStart', obtendrás 'From AStart'.
¿Alguna idea sobre arreglar esto?
fuente
if (char.IsUpper(text[i]) && !(char.IsUpper(text[i - 1]) && char.IsUpper(text[i + 1])))
Resultado de la prueba: "Desde el inicio", "Desde el inicio", "Desde el inicio", pero necesitai < text.Length - 1
en la condición de bucle for ignorar el último carácter y evitar una excepción fuera de rango.Aquí está el mío:
fuente
<pre><code>code</code></pre>
bloque en lugar de la sintaxis Markdown. No es necesario que lo rebajes (si fueras tú).Asegúrese de que no están poniendo espacios al principio de la cadena, pero que están poniéndolos entre capitales consecutivos. Algunas de las respuestas aquí no abordan uno o ambos de esos puntos. Hay otras formas además de expresiones regulares, pero si prefiere usar eso, intente esto:
El
\B
es un negado\b
, por lo que representa un límite sin palabras. Significa que el patrón coincide con "Y" enXYzabc
, pero no enYzabc
oX Yzabc
. Como un pequeño bono, puede usar esto en una cadena con espacios y no los duplicará.fuente
Esta expresión regular coloca un carácter de espacio delante de cada letra mayúscula:
Tenga en cuenta el espacio en el frente si "$ 1 $ 2", esto es lo que lo hará.
Este es el resultado:
fuente
"([A-Z0-9])([a-z]*)"
Lo que tienes funciona perfectamente. Solo recuerde reasignar
value
el valor de retorno de esta función.fuente
Así es como puedes hacerlo en SQL
fuente
Inspirado en @MartinBrown, Two Lines of Simple Regex, que resolverá su nombre, incluidos Acyronyms en cualquier parte de la cadena.
fuente
fuente
fuente
En Ruby, a través de Regexp:
fuente
Tomé la excelente solución de Kevin Strikers y la convertí a VB. Como estoy bloqueado en .NET 3.5, también tuve que escribir IsNullOrWhiteSpace. Esto pasa todas sus pruebas.
fuente
La pregunta es un poco antigua, pero hoy en día hay una buena biblioteca en Nuget que hace exactamente esto, así como muchas otras conversiones a texto legible por humanos.
Echa un vistazo a Humanizer en GitHub o Nuget.
Ejemplo
fuente
Parece una buena oportunidad para
Aggregate
. Esto está diseñado para ser legible, no necesariamente especialmente rápido.fuente
Además de la respuesta de Martin Brown, también tuve un problema con los números. Por ejemplo: "Location2" o "Jan22" deben ser "Location 2" y "Jan 22" respectivamente.
Aquí está mi expresión regular para hacer eso, usando la respuesta de Martin Brown:
Aquí hay un par de sitios geniales para descubrir qué significa cada parte también:
Analizador de expresiones regulares basado en Java (pero funciona para la mayoría de expresiones regulares .net)
Analizador basado en script de acción
La expresión regular anterior no funcionará en el sitio del script de acción a menos que reemplace todo
\p{Ll}
con[a-z]
,\p{Lu}
con[A-Z]
y y\p{Nd}
con[0-9]
.fuente
Aquí está mi solución, basada en la sugerencia y construcción de Binary Worriers en los comentarios de Richard Priddys, pero también teniendo en cuenta que puede existir espacio en blanco en la cadena provista, por lo que no agregará espacio en blanco junto al espacio en blanco existente.
fuente
Para cualquiera que esté buscando una función C ++ que responda a esta misma pregunta, puede usar lo siguiente. Esto se basa en la respuesta dada por @Binary Worrier. Este método solo conserva acrónimos automáticamente.
Las cadenas de prueba que utilicé para esta función, y los resultados son:
fuente
Una solución C # para una cadena de entrada que consta solo de caracteres ASCII. La expresión regular incorpora una mirada hacia atrás negativa para ignorar una letra mayúscula (mayúscula) que aparece al comienzo de la cadena. Utiliza Regex.Replace () para devolver la cadena deseada.
También vea la demostración de regex101.com .
Rendimiento esperado:
Actualización: Aquí hay una variación que también manejará acrónimos (secuencias de letras mayúsculas).
Consulte también la demostración de regex101.com y la demostración de ideone.com .
Rendimiento esperado:
fuente
Aquí hay una solución más completa que no pone espacios delante de las palabras:
Nota: He usado múltiples expresiones regulares (no conciso, pero también manejará siglas y palabras de una sola letra)
En :
Fuera :
fuente
Todas las respuestas anteriores parecían demasiado complicadas.
Tenía una cadena que tenía una combinación de mayúsculas y _ así que, string.Replace () para hacer _, "" y usé lo siguiente para agregar un espacio en mayúsculas.
fuente
Inspirado por la respuesta de Binary Worrier, di un giro ante esto.
Aquí está el resultado:
Hice la prueba con cronómetro ejecutando 10000000 iteraciones y varias longitudes de cadena y combinaciones.
En promedio 50% (quizás un poco más) más rápido que la respuesta de Binary Worrier.
fuente
fuente
Este incluye acrónimos y acrónimos en plural y es un poco más rápido que la respuesta aceptada:
Pasa estas pruebas:
fuente
Una implementación con
fold
, también conocida comoAggregate
:Además de la solicitud, esta implementación guarda correctamente espacios y acrónimos iniciales, internos y finales, por ejemplo,
fuente
Una manera simple de agregar espacios después de letras minúsculas, letras mayúsculas o dígitos.
fuente