Repita char n veces en el mensaje zsh

Repita char n veces en el mensaje zsh

Estoy trabajando en un mensaje ZSH personalizado y quiero repetir un carácter nen una cadena (como espacios para relleno). Esta cadena está impresa con print -rP(la -rbandera ignora las convenciones de escape de eco y la -Pbandera realiza expansiones rápidas).

Tengo un código de trabajo que utiliza algún tipo de sustitución de cadenas, pero no sé cómo funciona. Por alguna razón, tengo que multiplicar el número de caracteres que quiero imprimir por dos, lo que parece un truco.

$ n=3
$ c='a'
$ print -rP "${(l:$n::$c:)}" # why doesn't this work?
ca
$ print -rP "${(l:(( $n * 2 ))::$c:)}" # but this does?
aaa

Entonces, 1) ¿por qué funciona esto cuando se multiplica por dos y 2) cuál es la sintaxis correcta para repetir un carácter dentro de una cadena?

Respuesta1

1) ¿Por qué funciona esto cuando se multiplica por dos?

La expansión "${(l:3::$c:)}"se expande a c$cmientras que "${(l:3*2::$c:)}"se expande a $c$c$c. Si se establece la opción PROMPT_SUBSTy esta cadena se utiliza como parte de una cadena de solicitud, se evalúa la expansión de parámetros, la sustitución de comandos y la expansión aritmética. Entonces si c=a, entonces c$cse vuelve cay $c$c$cse vuelve aaa.

Prueba con XTRACEconjunto:

$ n=3 c=a zsh -o PROMPT_SUBST -xc 'print -rP -- "${(l:n::$c:)}"'
+zsh:1> print -rP -- 'c$c'
ca
$ n=3 c=a zsh -o PROMPT_SUBST -xc 'print -rP -- "${(l:n*2::$c:)}"'
+zsh:1> print -rP -- '$c$c$c'
aaa

y 2) ¿cuál es la sintaxis correcta para repetir un carácter dentro de una cadena?

El lindicador de expansión de parámetros se puede usar de la misma manera que ya lo está usando. Sin embargo, la pbandera debe usarse para permitir $cque el argumento de cadena se tome como el valor de la variable cantes del relleno (gracias @StéphaneChazelas por señalar esto).

$ n=3 c=a zsh -xc 'print -r -- "${(pl:n::$c:)}"'
+zsh:1> print -r -- aaa
aaa

Tenga en cuenta que esta es la única forma de expansión de parámetros aceptada por esta construcción, según man zshexpn(en la sección sobre Indicadores de expansión de parámetros):

p   Reconozca las mismas secuencias de escape que los printargumentos de cadena integrados para cualquiera de los indicadores descritos a continuación que siguen a este argumento.

Alternativamente, con esta opción los argumentos de cadena pueden tener la forma $varen cuyo caso se sustituye el valor de la variable. Tenga en cuenta que este formulario es estricto; el argumento de cadena no sufre una expansión de parámetros general.

Respuesta2

Usando su notación original, puede lograr lo que deseaba, usando pal mismo tiempocomienzode las banderas de parámetros

 print "${(pl:$n::$c:)}"

Para obtener más información y algunos otros ejemplos útiles, consulte la sección5.4.6: Aún más indicadores de parámetrosenCapítulo 5: Sustitucionesde la guía zsh. Menciona mayúsculas P, pero no p:


Aquí hay algunas otras marcas de parámetros; Estoy repitiendo algunos de estos. Uno muy útil es tdecirte el tipo de parámetro. Esto también surgió en el capítulo 3. Su uso más común es probar el tipo básico del parámetro antes de intentar usarlo:

  if [[ ${(t)myparam} != *assoc* ]]; then
    # $myparam is not an associative array.  Do something about it.
  fi

Otro tipo muy útil es para el relleno izquierdo o derecho de una cadena, hasta una longitud específica y, opcionalmente, con una cadena de relleno especificada para usar en lugar de espacio; incluso puede especificar una cadena única para que vaya justo al lado de la cadena en cuestión.

  foo='abcdefghij'
  for (( i = 1; i <= 10; i++ )); do
   goo=${foo[1,$i]}
   print ${(l:10::X::Y:)goo} ${(r:10::X::Y:)goo}
  done

imprime lo bastante bonito:

  XXXXXXXXYa aYXXXXXXXX
  XXXXXXXYab abYXXXXXXX
  XXXXXXYabc abcYXXXXXX
  XXXXXYabcd abcdYXXXXX
  XXXXYabcde abcdeYXXXX
  XXXYabcdef abcdefYXXX
  XXYabcdefg abcdefgYXX
  XYabcdefgh abcdefghYX
  Yabcdefghi abcdefghiY
  abcdefghij abcdefghij

Tenga en cuenta que esos dos puntos (que pueden ser otros caracteres, como expliqué para las banderas ( s) y ( j)) siempre aparecen en pares antes y después del argumento, de modo que con tres argumentos, los dos puntos intermedios se duplican. Puedes perderte la :Y:parte y la :X:parte y ver qué pasa. No es necesario que las cadenas de relleno sean caracteres individuales; si no caben un número exacto de veces en el espacio de relleno, la última repetición se truncará en el extremo más alejado del argumento del parámetro que se inserta.

Dos parámetros le dicen al shell que desea que se haga algo especial con el valor de sustitución del parámetro. El Pindicador ( ) obliga a que el valor se trate como un nombre de parámetro, de modo que se obtiene el efecto de una doble sustitución:

  % final=string
  % intermediate=final
  % print ${(P)intermediate}
  string

Esto es un poco como si $intermediatefuera lo que en ksh se llama a nameref, un parámetro que se marca como referencia a otro parámetro. Es posible que Zsh eventualmente también los tenga; hay lugares donde son mucho más convenientes que la (P)bandera.

Una bandera más poderosa es ( e), que obliga a volver a escanear el valor para todas las formas de sustitución de una sola palabra. Por ejemplo,

  % foo='$(print $ZSH_VERSION)'
  % print ${(e)foo}
  4.0.2

hizo que el valor de $foofuera reexaminado, momento en el cual se encontró y ejecutó la sustitución del comando.

Las banderas restantes son algunos trucos de formato especiales simples: ordenar los elementos de la matriz en orden léxico normal (caracteres) con ( o), ordenar en orden inverso con ( O), hacer lo mismo entre mayúsculas y minúsculas de forma independiente con ( oi) o ( Oi) respectivamente, expandir el mensaje %- escapa con ( %) (fácil de recordar), expande la barra invertida escapa como lo hace print con p, fuerza todos los caracteres a mayúsculas con ( U) o minúsculas con ( L), escribe en mayúscula el primer carácter de la cadena o cada elemento de la matriz con ( C), aparece caracteres especiales como secuencias de escape con ( V). Eso debería ser suficiente para seguir adelante.

información relacionada