Mercedes, miembro de este equipo de trabajo, nos ha hecho el favor de escribir esta crónica porque conoce perfectamente este tema.
Solución:
Debe evaluar el elemento actual y obtener la longitud del mismo. Si la longitud es inferior a 4, utilícela en la función de subcadena.
foreach ($str in "hello", "good morning", "hi")
$str.subString(0, [System.Math]::Min(4, $str.Length))
O puede mantenerlo simple, usando la alternativa de PowerShell a un operador ternario:
foreach ($str in "hello", "good morning", "hi")
$(if ($str.length -gt 4) $str.substring(0, 4) else $str )
Si bien todas las demás respuestas son “correctas”, sus eficiencias van de subóptimas a potencialmente horrendas. Lo siguiente no es una crítica de las otras respuestas, pero pretende ser una comparación instructiva de su funcionamiento subyacente. Después de todo, la creación de secuencias de comandos se trata más de hacer que se ejecute pronto que de hacerlo rápido.
En orden:
-
foreach ($str in "hello", "good morning", "hi") $str.subString(0, [System.Math]::Min(4, $str.Length))
Esto es básicamente lo mismo que mi oferta, excepto que en lugar de devolver $str cuando es demasiado corto, llamamos a substring y le decimos que devuelva el valor completo. string. Por lo tanto, subóptimo. Todavía está haciendo if..then..else pero solo dentro de Min, vis.
if (4 -lt $str.length) 4 else $str.length
-
foreach ($str in "hello", "good morning", "hi") $str -replace '(.4).+','$1'
Usando la coincidencia de expresiones regulares para tomar los primeros cuatro caracteres y luego reemplazar todo string con ellos significa que todo el (posiblemente muy largo) string debe ser escaneado por el motor de comparación de complejidad/eficiencia desconocida.
Mientras que una persona puede ver que el ‘.+’ es simplemente para hacer coincidir todo el resto de la string, el motor de comparación podría estar creando una gran lista de alternativas de retroceso ya que el patrón no está anclado (sin ^ al principio). La parte inteligente (no descrita) aquí es que si el string tiene menos de cinco caracteres (cuatro veces
.
seguido de uno o más.
) entonces toda la coincidencia falla y replace devuelve $str sin cambios. -
foreach ($str in "hello", "good morning", "hi") try $str.subString(0, 4) catch [ArgumentOutOfRangeException] $str
Lanzar excepciones deliberadamente en lugar de la verificación programática de límites es una solución interesante, pero quién sabe qué sucede cuando la excepción surge desde el bloque de prueba hasta la captura. Probablemente no mucho en este caso simple, pero no sería una práctica general recomendada, excepto en situaciones donde hay muchas posibles fuentes de errores (lo que hace que sea engorroso verificarlas todas), pero solo unas pocas respuestas.
Curiosamente, una respuesta a una pregunta similar en otro lugar usando -join
y array rebanadas (que no causan errores en el índice fuera de rango, simplemente ignore los elementos que faltan):
$str[0..3] -join "" # Infix
(o más simplemente)
-join $str[0..3] # Prefix
podría ser el más eficiente (con la optimización adecuada) dada la gran similitud entre el almacenamiento de string
y char[]
. Sería necesaria la optimización ya que, de forma predeterminada, $str[0..3] es un objeto[]cada elemento es un solo carácter, por lo que se parece poco a un string (en memoria). Darle a PowerShell una pequeña pista podría ser útil,
-join [char[]]$str[0..3]
Sin embargo, tal vez solo diciéndole lo que realmente quiere,
new-object string (,$str[0..3]) # Need $str[0..3] to be a member of an array of constructor arguments
invocando así directamente
new String(char[])
es mejor.
Valoraciones y reseñas
Al final de todo puedes encontrar las notas de otros desarrolladores, tú igualmente puedes dejar el tuyo si te apetece.