Tengo la siguiente cadena:

x = "marchTextIWantToDisplayWithSpacesmarch"

Me gustaría eliminar la parte de 'marcha' al comienzo de la cadena y luego agregar un espacio antes de cada letra mayúscula en el resto para obtener el siguiente resultado:

"Text I Want To Display With Spacesmarch"

Para insertar espacios en blanco, utilicé gsub("([a-z]?)([A-Z])", "\\1 \\2", x, perl= T) pero no tengo idea de cómo modificar el patrón para que la primera 'marcha' se excluya de la cadena devuelta. Estoy tratando de mejorar en esto para que cualquier ayuda sea muy apreciada.

3
user51462 10 may. 2019 a las 07:00

4 respuestas

La mejor respuesta

No, no puede lograr su reemplazo con un solo gsub porque en uno de sus requisitos, desea eliminar todas las letras minúsculas que comienzan desde el principio, y su segundo requisito es introducir un espacio antes de cada letra mayúscula, excepto el primera letra mayúscula de la cadena resultante después de eliminar todas las letras minúsculas del comienzo del texto.

Habría sido posible hacerlo en una sola llamada gsub en casos en los que de alguna manera podemos reutilizar algunos de los caracteres existentes para hacer el reemplazo condicional que no puede ser el caso aquí. Entonces, en el primer paso, puede usar la expresión regular ^[a-z]+ para deshacerse de todas las letras minúsculas solo desde el comienzo de la cadena,

sub('^[a-z]+', '', "marchTextIWantToDisplayWithSpacesmarch")

Dejándote con esto

[1] "TextIWantToDisplayWithSpacesmarch"

Y el siguiente paso puede utilizar esta expresión regular (?<!^)(?=[A-Z]) para insertar un espacio antes de cada letra mayúscula, excepto la primera, ya que es posible que no desee un espacio adicional antes de su oración. Pero puedes combinar ambos y escribirlos así,

gsub('(?<!^)(?=[A-Z])', ' ', sub('^[a-z]+', '', "marchTextIWantToDisplayWithSpacesmarch"), perl=TRUE)

Que te dará la cuerda deseada,

[1] "Text I Want To Display With Spacesmarch"

Editar: Explicación del patrón (?<!^)(?=[A-Z])

Primero, tomemos el patrón (?=[A-Z]),

Vea los marcadores rosas en esta demostración

Como puede ver, en la demostración, cada letra mayúscula está precedida por una marca rosa que es el lugar donde se insertará un espacio. Pero no queremos que se inserte espacio antes de la primera letra, ya que no es necesario. Por lo tanto, necesitamos una condición en regex, que no seleccionará la primera letra mayúscula que aparece al comienzo de la cadena. Y para eso, debemos usar una mirada negativa detrás de (?<!^), lo que significa que No seleccione la posición precedida por el inicio de la cadena y, por lo tanto, esto (?<!^) ayuda a descartar la letra mayúscula precedida por solo el inicio de la cadena.

Vea esta demostración donde el marcador rosa ha desaparecido de la primera letra mayúscula

Espero que esto aclare cómo se selecciona cada letra mayúscula pero no la primera. Avíseme si tiene alguna consulta adicional.

4
Pushpesh Kumar Rajwanshi 10 may. 2019 a las 05:23

Puede usar una sola llamada de expresión regular a gsub junto con trimws para recortar la cadena resultante:

trimws(gsub("^\\p{Ll}+|(?<=.)(?=\\p{Lu})", " ", x, perl=TRUE))
## => [1] "Text I Want To Display With Spacesmarch"

También es compatible con todas las letras minúsculas Unicode (\p{Ll}) y mayúsculas (\p{Lu}).

Consulte la R demo en línea y la demostración de expresiones regulares.

Detalles

  • ^\\p{Ll}+ - 1 o más letras minúsculas al comienzo de la cadena
  • | - o
  • (?<=.)(?=\\p{Lu}): cualquier ubicación entre cualquier carácter excepto caracteres de salto de línea y una letra mayúscula.

Aquí hay una alternativa con una sola llamada a gsubfn regex con alguna lógica ifelse:

> gsubfn("^\\p{Ll}*(\\p{L})|(?<=.)(?=\\p{Lu})", function(n) ifelse(nchar(n)>0,n," "), x, perl=TRUE,backref=-1) 
[1] "Text I Want To Display With Spacesmarch"

Aquí, la parte ^\\p{Ll}*(\\p{L}) coincide con más de 0 letras minúsculas y captura la siguiente mayúscula en el Grupo 1 al que se accederá pasando el argumento n a la función anónima. Si la longitud n no es cero, esta alternativa coincide y debemos reemplazarla con este valor. De lo contrario, reemplazamos con un espacio.

3
Wiktor Stribiżew 10 may. 2019 a las 09:26

Una opción sería capturar la letra mayúscula como un grupo ((...)) y en el reemplazo crear un espacio seguido de la referencia (\\1) del grupo capturado

gsub("([A-Z])", " \\1", x)
#[1] "march Text I Want To Display With Spacesmarch"

Si necesitamos eliminar la 'marcha'

sub("\\b[a-z]\\w+\\s+", "", gsub("([A-Z])", " \\1", x))
[#1] "Text I Want To Display With Spacesmarch"

Datos

x <- "marchTextIWantToDisplayWithSpacesmarch"
5
akrun 10 may. 2019 a las 04:01

Como esto está etiquetado como Perl, mis 2 centavos:

¿Puedes encadenar las sustituciones dentro de sub() y gsub()? En las versiones perl más nuevas, se puede agregar una opción /r a la sustitución s/// para que la cadena coincidente pueda ser devuelta "no destructivamente" y luego emparejada nuevamente. Esto permite coincidencias / sustituciones / revanchas sin dominar sintaxis avanzada, por ejemplo :

perl -E '
  say "marchTextIWantToDisplayWithSpacesmarch" =~
  s/\Amarch//r =~ s/([[:upper:]])/ $1/gr  =~ s/\A\s//r;'

Salida

Text I Want To Display With Spacesmarch

Esto parece ser lo que están haciendo @ pushpesh-kumar-rajwanshi y @akrun envolviendo gsub dentro de sub() (y viceversa). En general, no creo que perl = T capture la locura magníficamente avanzada de perl regexps ;-) pero gsub/sub debe funcionar rápidamente en vectores, ¿no?

1
G. Cito 10 may. 2019 a las 08:27