Nuestro grupo de especialistas despúes de días de investigación y de recopilar de datos, obtuvimos la respuesta, deseamos que todo este artículo sea de utilidad en tu trabajo.
Solución:
Si bien la útil respuesta de Keith Hill le muestra cómo cambiar la cultura actual de un script a pedido (alternativa más moderna a partir de PSv3 + y .NET Framework v4.6 +:[cultureinfo]::CurrentCulture = [cultureinfo]::InvariantCulture
), hay no hay necesidad de cambiar la cultura, porque, como descubrió en la segunda actualización de la pregunta, De PowerShell string interpolación (en lugar de usar el -f
operador) siempre utiliza el invariante en lugar del Actual cultura:
En otras palabras:
Si reemplaza 'val: 0' -f 1.2
con "val: $(1.2)"
, el literal 1.2
es no formateado de acuerdo con las reglas de la cultura actual.
Puede verificar en la consola ejecutando (en una sola línea; PSv3 +, .NET framework v4.6 +):
PS> [cultureinfo]::currentculture = 'de-DE'; 'val: 0' -f 1.2; "val: $(1.2)"
val: 1,2 # -f operator: GERMAN culture applies, where ',' is the decimal mark
val: 1.2 # string interpolation: INVARIANT culture applies, where '.' is the decimal mark.
Fondo:
Asombrosamente, Potencia Shell siempre aplica el invariante en lugar del Actual cultura en el siguiente string-relacionado contextos, si el tipo en cuestión admite la conversión específica de la cultura hacia y desde cadenas:
Como se explica en esta respuesta detallada, PowerShell solicita explícitamente invariante de cultura Procesando – pasando el [cultureinfo]::InvariantCulture
instancia – en los siguientes escenarios:
-
Cuando string-interpolando: si el tipo del objeto implementa el
IFormattable
interfaz; de lo contrario, PowerShell llama.psobject.ToString()
en el objeto. -
Cuando fundición:
- para a string, incluso cuando vinculante a un
[string]
-parámetro de tipo: si el tipo de fuente implementa el[IFormattable]
interfaz; de lo contrario, PowerShell llama.psobject.ToString()
. - de a string: si el tipo de destino static
.Parse()
El método tiene una sobrecarga con un[IFormatProvider]
-parámetro de tipo (que es una interfaz implementada por[cultureinfo]
).
- para a string, incluso cuando vinculante a un
-
Cuando string-comparar (
-eq
,-lt
,-gt
) , utilizando elString.Compare()
sobrecarga que acepta unCultureInfo
parámetro. -
¿Otros?
En cuanto a para qué es / es la cultura invariante:
La cultura invariante es insensible a la cultura; está asociado con el idioma inglés pero no con ningún país / región.
[…]A diferencia de los datos sensibles a la cultura, que están sujetos a cambios por personalización del usuario o por actualizaciones de .NET Framework o el sistema operativo, los datos culturales invariables son estable a lo largo del tiempo y en todas las culturas instaladas y los usuarios no pueden personalizarlo. Esto hace que la cultura invariante sea particularmente útil para operaciones que requieren resultados independientes de la cultura, como operaciones de formato y análisis que conservan datos formateados, u operaciones de clasificación y orden que requieren que los datos se muestren en un orden fijo independientemente de la cultura.
Presumiblemente, es la estabilidad entre culturas lo que motivó a los diseñadores de PowerShell a usar consistentemente la cultura invariante cuando implícitamente convertir hacia y desde cadenas.
Por ejemplo, si codifica una fecha string tal como '7/21/2017'
en un script y luego intente convertirlo a la fecha con un [date]
cast, el comportamiento invariante de la cultura de PowerShell garantiza que el script no se rompa incluso cuando se ejecuta mientras está en vigor una cultura que no sea el inglés de EE. UU. afortunadamente, la cultura invariante también reconoce cadenas de fecha y hora en formato ISO 8601;
p.ej, [datetime] '2017-07-21'
también funciona.
Por otro lado, si quieres convertir ay desde Actual-cadenas apropiadas para la cultura, debes hacerlo explícitamente.
Para resumir:
-
Mudado para instrumentos de cuerda:
- Incrustación de instancias de tipos de datos con valores culturales de forma predeterminada string representaciones en el interior
"..."
produce una culturainvariante representación[double]
o[datetime]
son ejemplos de tales tipos). - Conseguir un Actual-representación cultural, convocatoria
.ToString()
explícitamente o usar-f
, el operador de formato (posiblemente dentro"..."
a través de un cerramiento$(...)
).
- Incrustación de instancias de tipos de datos con valores culturales de forma predeterminada string representaciones en el interior
-
Mudado de instrumentos de cuerda:
-
Un elenco directo (
[
) solo reconoce la cultura-invariante string representaciones.] ... -
Para convertir de un Actualapropiado para la cultura string representación (o una específico la representación de la cultura), utilice el tipo de destino static
::Parse()
método explícitamente (opcionalmente con un explícito[cultureinfo]
instancia para representar una cultura específica).
-
Ejemplos de cultura INVARIANTE:
-
string interpolación y yesos:
-
"$(1/10)"
y[string] 1/10
- ambos rinden string literal
0.1
, con marca decimal.
, independientemente de la cultura actual.
- ambos rinden string literal
-
Similar, yesos de instrumentos de cuerda son invariantes con respecto a la cultura; p.ej,
[double] '1.2'
.
es siempre reconocido como la marca decimal, independientemente de la cultura actual.- Otra forma de decirlo:
[double] 1.2
es no traducido a la cultura-sensible-sobrecarga de método por defecto[double]::Parse('1.2')
, pero a la cultura-invariante[double]::Parse('1.2', [cultureinfo]::InvariantCulture)
-
-
string comparación (asumir que
[cultureinfo]::CurrentCulture='tr-TR'
está en efecto – turco, dondei
NO es una representación en minúsculas deI
)[string]::Equals('i', 'I', 'CurrentCultureIgnoreCase')
$false
con la cultura turca en vigor.'i'.ToUpper()
muestra que en la cultura turca la mayúscula esİ
, noI
.
'i' -eq 'I'
- es todavía
$true
, porque el invariante se aplica la cultura. - implícitamente lo mismo que:
[string]::Equals('i', 'I', 'InvariantCultureIgnoreCase')
- es todavía
Ejemplos sensibles a la cultura:
Se respeta la cultura actual en los siguientes casos:
-
Con
-f
, los string-operador de formato (como se señaló anteriormente):[cultureinfo]::currentculture = 'de-DE'; '0' -f 1.2
rendimientos1,2
- Escollo: debido a la precedencia del operador, cualquier expresión como el RHS de
-f
debe estar encerrado en(...)
para ser reconocido como tal:- P.ej,
'0' -f 1/10
se evalúa como si('0' -f 1) / 10
había sido especificado;
usar'0' -f (1/10)
en lugar de.
- P.ej,
-
Defecto salida a la consola:
-
p.ej,
[cultureinfo]::CurrentCulture = 'de-DE'; 1.2
rendimientos1,2
-
Lo mismo se aplica a la salida de cmdlets; p.ej,
[cultureinfo]::CurrentCulture = 'de-DE'; Get-Date '2017-01-01'
rendimientosSonntag, 1. Januar 2017 00:00:00
-
Consideración: Parece haber un insecto a partir de Windows PowerShell v5.1 / PowerShell Core v6.0.0-beta.5: en ciertos escenarios, los literales pasados a un bloque de script como parámetros no restringidos pueden dar como resultado una salida predeterminada que no varía según la cultura; consulte este problema de GitHub
-
-
Al escribir a un expediente con
Set-Content
/Add-Content
oOut-File
/>
/>>
:- p.ej,
[cultureinfo]::CurrentCulture = 'de-DE'; 1.2 > tmp.txt; Get-Content tmp.txt
rendimientos1,2
- p.ej,
-
Al usar el static
::Parse()
/::TryParse()
métodos sobre tipos de números como[double]
mientras pasa solo el string analizar; por ejemplo, con culturafr-FR
en efecto (donde,
es la marca decimal),[double]::Parse('1,2')
devuelve el doble1.2
(es decir,1 + 2/10
).- Consideración: Como señala bviktor, los separadores de miles se reconocen de forma predeterminada, pero de una manera muy flexible: efectivamente, el separador de miles se puede colocar en cualquier sitio dentro de la porción entera, independientemente de cuántos dígitos haya en los grupos resultantes, y un
0
también se acepta; por ejemplo, en elen-US
cultura (donde,
es el separador de miles),[double]::Parse('0,18')
quizás sorprendentemente triunfa y rinde18
.- Para suprimir el reconocimiento de separadores de miles, use algo como
[double]::Parse('0,18', 'Float')
, mediante elNumberStyles
parámetro
- Para suprimir el reconocimiento de separadores de miles, use algo como
- Consideración: Como señala bviktor, los separadores de miles se reconocen de forma predeterminada, pero de una manera muy flexible: efectivamente, el separador de miles se puede colocar en cualquier sitio dentro de la porción entera, independientemente de cuántos dígitos haya en los grupos resultantes, y un
-
Involuntario sensibilidad cultural que no se corregirá para preservar la compatibilidad con versiones anteriores:
- En conversiones de tipo de enlace de parámetros para compilado cmdlets (pero Código de PowerShell – scripts o funciones – es cultura invariante): consulte este problema de GitHub.
- En el
-as
operador – ver este problema de GitHub. - En
[hashtable]
key búsquedas – vea esta respuesta y este problema de GitHub. - [Decision pending] En el LHS de
-replace
operaciones – vea este problema de GitHub.
-
¿Otros?
Esta es una función de PowerShell que uso para probar secuencias de comandos en otras culturas. Creo que podría usarse para lo que buscas:
function Using-Culture ([System.Globalization.CultureInfo]$culture =(throw "USAGE: Using-Culture -Culture culture -Script scriptblock"),
[ScriptBlock]$script=(throw "USAGE: Using-Culture -Culture culture -Script scriptblock"))
$OldCulture = [System.Threading.Thread]::CurrentThread.CurrentCulture
$OldUICulture = [System.Threading.Thread]::CurrentThread.CurrentUICulture
try
[System.Threading.Thread]::CurrentThread.CurrentCulture = $culture
[System.Threading.Thread]::CurrentThread.CurrentUICulture = $culture
Invoke-Command $script
finally
[System.Threading.Thread]::CurrentThread.CurrentCulture = $OldCulture
[System.Threading.Thread]::CurrentThread.CurrentUICulture = $OldUICulture
PS> $res = Using-Culture fr-FR 1.1
PS> $res
1.1
Estaba pensando en cómo hacerlo más fácil y se me ocurrieron aceleradores:
Add-type -typedef @"
using System;
public class InvFloat
double _f = 0;
private InvFloat (double f)
_f = f;
private InvFloat(string f)
_f = Double.Parse(f, System.Globalization.CultureInfo.InvariantCulture);
public static implicit operator InvFloat (double f)
return new InvFloat(f);
public static implicit operator double(InvFloat f)
return f._f;
public static explicit operator InvFloat (string f)
return new InvFloat (f);
public override string ToString()
return _f.ToString(System.Globalization.CultureInfo.InvariantCulture);
"@
$acce = [type]::gettype("System.Management.Automation.TypeAccelerators")
$acce::Add('f', [InvFloat])
$y = 1.5.ToString()
$z = ([f]1.5).ToString()
Espero que te ayude.
Aquí puedes ver las reseñas y valoraciones de los lectores
Si te mola la invitación, tienes la opción de dejar un artículo acerca de qué te ha impresionado de este enunciado.