PowerShell,在另一种文化中格式化值
PowerShell中有一种简单的方法来在另一个语言环境中格式化数字之类的东西吗? 我目前正在编写几个函数来减轻我和SVG使用的SVG生成.
作为小数点分隔符,而PowerShell在将浮点数字转换为string时遵循我的语言环境设置( de-DE
)。
有没有一个简单的方法来设置另一个语言环境的function,所以不坚持
.ToString((New-Object Globalization.CultureInfo ""))
每一个double
variables?
注意:这是关于用于格式化的区域设置 , 而不是格式化string。
(旁边的问题:我应该使用这种情况下的不变文化,还是使用en-US
?)
ETA:那么,我在这里尝试的是如下所示:
function New-SvgWave([int]$HalfWaves, [double]$Amplitude, [switch]$Upwards) { "<path d='M0,0q0.5,{0} 1,0{1}v1q-0.5,{2} -1,0{3}z'/>" -f ( $(if ($Upwards) {-$Amplitude} else {$Amplitude}), ("t1,0" * ($HalfWaves - 1)), $(if ($Upwards -xor ($HalfWaves % 2 -eq 0)) {-$Amplitude} else {$Amplitude}), ("t-1,0" * ($HalfWaves - 1)) ) }
只是一些自动化的东西,我倾向于写所有的时间和双值需要使用小数点,而不是逗号(他们在我的区域使用)。
ETA2:有趣的琐事添加:
PS Home:> $d=1.23 PS Home:> $d 1,23 PS Home:> "$d" 1.23
通过将该variables放入一个string中,设置的语言环境似乎并不适用。
这是我用来testing其他文化脚本的PowerShellfunction。 我相信它可以用于你以后的事情:
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
我正在考虑如何让它变得简单,并提出加速器:
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()
我希望这会有所帮助。
虽然Keith Hill的有用答案显示了如何根据需要更改脚本的当前文化(更为现代的select,如PSv3 +和.NET框架v4.6 +:
[cultureinfo]::CurrentCulture = [cultureinfo]::InvariantCulture
), 没有必要改变文化 ,因为 – 正如你在问题的第二次更新中发现的那样 – PowerShell的string插值 (而不是使用-f
运营商)总是使用不变而不是当前的文化 :
换一种说法:
如果用"val: $(1.2)"
replace'val: {0}' -f 1.2
,那么文字1.2
将不会根据当前文化的规则进行格式化。
您可以通过运行( 在单行上 ; PSv3 +,.NET框架v4.6 +)在控制台中进行validation:
> [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.
背景:
令人惊讶的是, PowerShell 总是在下面的string相关的上下文中应用不变的,而不是当前的文化 , 如果这种types支持文化特定的string转换:
部分基于这个深入的答案 , PowerShell通过传递[cultureinfo]::InvariantCulture
实例来显式请求文化不变的处理 – 在以下情况下:
-
当string插值 :如果对象的types实现
IFormattable
接口; 否则,PowerShell将在对象上调用.psobject.ToString()
。 -
投射时 :
- 包括绑定到
[string]
-type参数时 :如果源types实现[IFormattable]
接口; 否则,PowerShell调用.psobject.ToString()
。 - 从一个string :如果目标types的静态
.Parse()
方法有一个[IFormatProvider]
-type参数(这是一个由[cultureinfo]
实现的接口.Parse()
的重载。
- 包括绑定到
-
当使用接受
CultureInfo
参数的String.Compare()
重载 string比较 (-eq
,-lt
,-gt
)时。 -
其他?
至于什么是不变的文化是:
不变的文化是文化不敏感的; 它与英语有关,但不与任何国家/地区有关 。
[…]
不同于对文化敏感的数据(用户自定义或通过更新.NET Framework或操作系统)可能会有所变化,不变的文化数据在一段时间内是稳定的,在所安装的文化中是稳定的,不能由用户自定义。 这使得不变文化特别适用于需要独立于文化的结果的操作,例如格式化和parsing操作(持久化格式化的数据),或sorting和sorting操作(需要数据以固定顺序显示而不pipe文化)。
据推测,跨文化的稳定性促使PowerShell的devise者在隐式地转换string和从string转换时始终如一地使用不变的文化 。
例如,如果您将一个datestring(例如'7/21/2017'
硬编码到脚本中,然后尝试使用[date]
转换将其转换为date,则PowerShell的文化不变行为可确保脚本不会在美国英语以外的文化运行时甚至可以保持平衡 – 幸运的是,不变文化还承认ISO 8601格式的date和时间string ;
例如[datetime] '2017-07-21'
也可以。
另一方面, 如果你想转换和从当前的文化适当的string,你必须明确这样做 。
总结:
-
转换为string :
- 在
"..."
embedded具有区分文化敏感度的string表示forms的数据types实例会产生不变的文化表示forms([double]
或[datetime]
就是这种types的示例)。 - 要获得当前的文化表示,请明确调用
.ToString()
或使用-f
格式化运算符(可能通过封闭的$(...)
)在"..."
。
- 在
-
从string转换 :
-
直接转换(
[<type>] ...
)只能识别文化不变的string表示。 -
要从当前文化适当的string表示(或特定的文化表示)转换,明确使用目标types的static
::Parse()
方法(可选地使用明确的[cultureinfo]
实例来表示特定的文化)。
-
文化 – INVARIANT例子:
-
string插值和强制转换 :
-
"$(1/10)"
和[string] 1/10
- 这两个string的字面量都是
0.1
,带有小数点.
,而不考虑当前的文化。
- 这两个string的字面量都是
-
同样, 从string转换文化不变, 例如
[double] '1.2'
-
.
总是被认为是小数点,而不考虑当前的文化。 - 另一种说法是:
[double] 1.2
不会被翻译成文化敏感的默认方法overload[double]::Parse('1.2')
,而是文化不变的[double]::Parse('1.2', [cultureinfo]::InvariantCulture)
-
-
-
string比较 (假设
[cultureinfo]::CurrentCulture='tr-TR'
是有效的 – 土耳其语,其中i
不是I
的小写表示 )-
[string]::Equals('i', 'I', 'CurrentCultureIgnoreCase')
-
$false
土耳其文化有效。 -
'i'.ToUpper()
表明在土耳其文化中,大写字母是İ
,而不是I
-
-
'i' -eq 'I'
- 仍然是
$true
,因为不变的文化是应用的。 - 隐含的相同:
[string]::Equals('i', 'I', 'InvariantCultureIgnoreCase')
- 仍然是
-
文化敏感的例子:
在以下情况下,尊重当前的文化:
-
使用
-f
,string格式操作符 (如上所述):-
[cultureinfo]::currentculture = 'de-DE'; '{0}' -f 1.2
[cultureinfo]::currentculture = 'de-DE'; '{0}' -f 1.2
产生1,2
- 陷阱:由于运算符的优先级 ,作为
-f
的RHS的任何expression式都必须包含在(...)
中以便被识别为:- 例如,
'{0}' -f 1/10
被评估为if('{0}' -f 1) / 10
;
改为使用'{0}' -f (1/10)
。
- 例如,
-
-
默认输出到控制台 :
-
例如
[cultureinfo]::CurrentCulture = 'de-DE'; 1.2
[cultureinfo]::CurrentCulture = 'de-DE'; 1.2
产量1,2
-
这同样适用于从cmdlet输出; 例如,
[cultureinfo]::CurrentCulture = 'de-DE'; Get-Date '2017-01-01'
[cultureinfo]::CurrentCulture = 'de-DE'; Get-Date '2017-01-01'
产量
Sonntag, 1. Januar 2017 00:00:00
-
警告 :在Windows PowerShell v5.1 / PowerShell Core v6.0.0-beta.5中似乎存在一个错误 :在某些情况下,作为不受约束的parameter passing给脚本块的文字会导致文化不变的默认输出 – 请参阅https ://github.com/PowerShell/PowerShell/issues/4545
-
-
使用
Set-Content
/Add-Content
或Out-File
/>
/>>
写入文件时 :- 例如
[cultureinfo]::CurrentCulture = 'de-DE'; 1.2 > tmp.txt; Get-Content tmp.txt
[cultureinfo]::CurrentCulture = 'de-DE'; 1.2 > tmp.txt; Get-Content tmp.txt
[cultureinfo]::CurrentCulture = 'de-DE'; 1.2 > tmp.txt; Get-Content tmp.txt
产生1,2
- 例如
-
其他?
如果您已经在您的环境中加载了文化,
#>Get-Culture LCID Name DisplayName ---- ---- ----------- 1031 de-DE German (Germany) #>Get-UICulture LCID Name DisplayName ---- ---- ----------- 1033 en-US English (United States)
有可能解决这个问题:
PS Home:> $d=1.23 PS Home:> $d 1,23
喜欢这个:
$d.ToString([cultureinfo]::CurrentUICulture) 1.23
当然,你需要记住,如果其他用户使用不同的语言环境设置来运行脚本,结果可能不会按照原来的devise。
不过,这个解决scheme可能会有用。 玩的开心!