代码之家  ›  专栏  ›  技术社区  ›  Joey

PowerShell,格式化其他区域性中的值

  •  6
  • Joey  · 技术社区  · 14 年前

    在PowerShell中,是否有一种简单的方法可以在其他区域设置数字等格式?我目前正在编写一些函数来简化我和SVG的生成。 . 作为十进制分隔符,PowerShell支持我的区域设置( de-DE )将浮点数转换为字符串时。

    有没有一种简单的方法可以为函数设置另一个区域设置,而不必粘贴

    .ToString((New-Object Globalization.CultureInfo ""))
    

    之后每 double 变量?

    注意:这是关于 现场 用于格式化, 格式字符串。

    (旁白:在这种情况下,我应该使用不变的文化,还是更确切地说 en-US ?)

    埃塔: 好吧,我在这里尝试的是如下内容:

    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))
        )
    }
    

    对于我经常写的东西,只需要一点自动化,双精度值需要使用小数点而不是逗号(它们在我的语言环境中使用)。

    小精灵: 添加有趣的琐事:

    PS Home:> $d=1.23
    PS Home:> $d
    1,23
    PS Home:> "$d"
    1.23
    

    通过将变量放入字符串中,设置的区域设置似乎在某种程度上不适用。

    4 回复  |  直到 6 年前
        1
  •  9
  •   Keith Hill    14 年前

    这是一个PowerShell函数,我用于在其他区域性中测试脚本。我相信它可以用于你所追求的:

    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
    
        2
  •  8
  •   mklement0    6 年前

    同时 Keith Hill's helpful answer 演示如何根据需要更改脚本的当前区域性(从PSv3+和.NET Framework v4.6+开始更为现代的替代方案:
    [cultureinfo]::CurrentCulture = [cultureinfo]::InvariantCulture )有 不需要改变文化 ,因为-正如您在问题的第二次更新中发现的那样- PowerShell字符串 插值 (与使用 -f operator)始终使用 不变量 而不是 现在的 文化 :

    换句话说:

    如果你替换 'val: {0}' -f 1.2 具有 "val: $(1.2)" ,文字 1.2 按照当前文化的规则格式化。
    您可以在控制台中通过运行( 在一条线上 ;PSv3+,.NET框架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.
    

    背景:

    令人惊讶的是, PowerShell 总是 应用 不变量 而不是 现在的 以下文化 字符串相关 上下文 , 如果 现有类型支持与字符串之间的特定于区域性的转换:

    如中所述 this in-depth answer , PowerShell显式请求 文化不变量 处理 -通过 [cultureinfo]::InvariantCulture 实例-在以下情况下:

    • 什么时候? 字符串插值 :如果对象的类型实现 IFormattable 接口;否则,PowerShell调用 .psobject.ToString() 在对象上。

    • 什么时候? 铸造 :

      • 一根绳子 ,包括何时 绑定到 [string] -类型化参数 :如果源类型实现 [IFormattable] 接口;否则,PowerShell调用 .psObject.ToString()。 .
      • 一根绳子 :如果目标类型是静态的 .Parse() 方法的重载具有 [IFormatProvider] -类型化参数(它是由 [cultureinfo] )
    • 什么时候? 字符串比较 ( -eq , -lt , -gt ,使用 String.Compare() overload that accepts a CultureInfo parameter .

    • 其他人?

    至于什么 the invariant culture 适用于:

    不变的文化对文化不敏感;它是 与英语相关,但不与任何国家/地区相关 .
    […]
    与区域性敏感数据不同,这些数据可能会因用户自定义或对.NET框架或操作系统的更新而发生更改,不变的区域性数据是 随着时间的推移和跨安装文化的稳定 用户无法自定义。这使得不变的区域性对于需要与区域性无关的结果的操作特别有用,例如保持格式化数据的格式化和解析操作,或者要求以固定顺序显示数据的排序和排序操作,而不考虑区域性。

    大概是跨文化的稳定性促使PowerShell的设计人员在 含蓄地 转换为字符串或从字符串转换 .

    例如,如果硬编码日期字符串,例如 '7/21/2017' 转换为脚本,然后尝试将其转换为日期 [date] 强制转换,PowerShell的区域性不变行为确保脚本在运行时不会中断,而非美国英语的区域性有效。- 幸运的是,不变的区域性还可以识别ISO 8601格式的日期和时间字符串 ;
    例如., [datetime] '2017-07-21' 也可以。

    在另一面, 如果您想转换为和从 现在的 -培养适当的字符串,必须这样做 明确地 .

    总结如下:

    • 转换 :

      • 在内部嵌入具有区域性敏感的默认字符串表示形式的数据类型实例 "..." 产生一种文化- 不变量 代表( [double] [datetime] 是此类类型的例子)。
      • 得到一个 现在的 -文化代表,呼叫 .ToString() 明确或使用 -F ,格式化运算符(可能在 “……” 通过封闭 $(...) )
    • 转换 :

      • 直接演员( [<type>] ... )只有承认文化- 不变量 字符串表示。

      • 从…转换 现在的 -区域性适当的字符串表示(或 具体的 区域性的表示),使用目标类型的静态 ::Parse() 方法显式(可选使用显式 [文化信息] 表示特定区域性的实例)。


    文化不变量示例:

    • 字符串插值 铸件 :

      • "$(1/10)" [string] 1/10

        • 两个都是yield字符串文本 0.1 ,带小数点 . 无论当前文化如何。
      • 同样地, 铸件 文化是不变的;例如, [double] '1.2'

        • . 总是 被识别为十进制标记,与当前区域性无关。
        • 另一种说法是: [double] 1.2 翻译成文化- 敏感的 -默认方法重载 [double]::Parse('1.2') 但是对于文化- 不变量 [double]::Parse('1.2', [cultureinfo]::InvariantCulture)
    • 字符串比较 (假设 [cultureinfo]::CurrentCulture='tr-TR' 实际上是土耳其语,在哪里 i is NOT a lowercase representation of I )

      • [string]::Equals('i', 'I', 'CurrentCultureIgnoreCase')
        • $false 土耳其文化的影响。
        • 'i'.ToUpper() 表明在土耳其文化中,大写字母是 Ä° 不是 .
      • 'i' -eq 'I'
        • 仍然是 $true ,因为 不变量 应用了区域性。
        • 含蓄地同: [string]::Equals('i', 'I', 'InvariantCultureIgnoreCase')

    文化敏感的例子:

    在以下情况下,尊重当前文化:

    • -F ,字符串格式运算符 (如上所述):

      • [cultureinfo]::currentculture = 'de-DE'; '{0}' -f 1.2 产量 1,2
      • 陷阱:由于 operator precedence 任何 表达 作为 -F 必须封闭在 (...) 为了得到承认:
        • 例如。, '{0}' -f 1/10 被评估为 ('{0}' -f 1) / 10 已指定;
          使用 '{0}' -f (1/10) 相反。
    • 违约 输出到控制台 :

      • 例如., [cultureinfo]::CurrentCulture = 'de-DE'; 1.2 产量 1,2

      • 这同样适用于来自Cmdlet的输出;例如,
        [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开始:在某些情况下,作为不受约束的参数传递到脚本块的文本可能会导致区域性不变的默认输出-请参阅 this GitHub issue

    • 当写信给 文件 具有 Set-Content / Add-Content Out-File / > / >> :

      • 例如。, [cultureinfo]::CurrentCulture = 'de-DE'; 1.2 > tmp.txt; Get-Content tmp.txt 产量 1,2
    • 当使用静态 ::分析() / ::TryParse() 有关数字类型的方法,例如 [double] 只传递要分析的字符串;例如,使用区域性 fr-FR 有效(其中 , 是小数点)。 [double]::Parse('1,2') 返回双精度 一点二 (即, 1 + 2/10 )

      • 告诫 作为 bviktor 指出,默认情况下可以识别数千个分隔符,但使用非常松散的方式:实际上,可以放置数千个分隔符 在任何地方 在整数部分内,无论结果组中有多少个数字,以及一个前导 0 也被接受;例如,在 en-US 文化(哪里 , 是千位分隔符)。 [double]::Parse('0,18') 也许令人惊讶 成功 和收益率 18 .
    • 无意的 无法更正以保持向后兼容性的文化敏感性 :

    • 其他人?

        3
  •  4
  •   stej    14 年前

    我在想如何让它变得简单,然后想到了加速器:

    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()
    

    希望能有所帮助。

        4
  •  1
  •   Porky    7 年前

    如果您的环境中已经加载了文化,

        #>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
    

    当然,您需要记住,如果其他用户使用不同的区域设置运行脚本,结果可能不会如最初预期的那样。

    然而,这个解决方案可能会有用。玩得高兴!