12

PowerShellで、別のロケールで数値などをフォーマットする簡単な方法はありますか?私は現在、SVGの生成を容易にするためにいくつかの関数を書いていますが、SVGは.小数点記号として使用しますが、PowerShellはde-DE浮動小数点数を文字列に変換するときにロケール設定()を尊重します。

関数などに固執せずに別のロケールを設定する簡単な方法はありますか?

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

すべてのdouble変数の後?

注:これは、フォーマット文字列ではなく、フォーマットに使用されるロケールに関するものです。

(副次的な質問:その場合、不変の文化を使用する必要があり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))
    )
}

私はいつも書く傾向があり、double値はコンマ(私のロケールで使用)の代わりに小数点を使用する必要があります。

ETA2:追加する興味深い雑学:

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

変数を文字列に入れることによって、設定されたロケールはどういうわけか適用されないようです。

4

4 に答える 4

18

キースヒルの有益な回答は、スクリプトの現在の文化をオンデマンドで変更する方法を示していますが(PSv3+および.NETFramework v4.6 +以降のより現代的な代替手段:) 、文化を変更する必要はありませ
[cultureinfo]::CurrentCulture = [cultureinfo]::InvariantCultureん。質問に対する2回目の更新では、PowerShellの文字列補間演算子を使用するのではなく)は、常に現在のカルチャではなく不変条件を使用します。-f

言い換えると:

に置き換える'val: {0}' -f 1.2"val: $(1.2)"、リテラル1.2は現在のカルチャの規則に従ってフォーマットされません。( 1行で; 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.

バックグラウンド:

驚いたことに、PowerShellは、手元の型が文字列との間のカルチャ固有の変換をサポートしている場合、次の文字列関連のコンテキスト現在のカルチャではなく常に不変条件を適用します。

この詳細な回答で説明されているように、PowerShell[cultureinfo]::InvariantCultureは、次のシナリオで、インスタンスを渡すことにより、カルチャに依存しない処理を明示的に要求します。

  • 文字列補間の場合:オブジェクトのタイプがIFormattableインターフェイスを実装する場合。それ以外の場合、PowerShellは.psobject.ToString()オブジェクトを呼び出します。

  • キャスト時:

    • -typedパラメータにバインドする場合[string]含め、文字列に:ソースタイプが[IFormattable]インターフェイスを実装する場合。それ以外の場合、PowerShellはを呼び出します.psobject.ToString()
    • 文字列から:ターゲットタイプの静的.Parse()メソッドに、[IFormatProvider]-typedパラメーター(によって実装されるインターフェイス[cultureinfo])を使用したオーバーロードがある場合。
  • 文字列を比較する場合(-eq、、 ) -ltパラメータを受け入れるオーバーロードを-gt使用します。String.Compare()CultureInfo

  • その他?

不変文化とは何か/目的は次のとおりです。

不変の文化は文化に影響されません。英語に関連付けられていますが、国/地域には関連付けられていません。
[...]
ユーザーのカスタマイズまたは.NETFrameworkまたはオペレーティングシステムの更新によって変更される可能性があるカルチャに依存するデータとは異なり、不変のカルチャデータは、時間の経過とともにインストールされたカルチャ全体で安定しており、ユーザーがカスタマイズすることはできません。これにより、不変のカルチャは、フォーマットされたデータを保持するフォーマットおよび解析操作や、カルチャに関係なくデータを固定順序で表示する必要があるソートおよび順序付け操作など、カルチャに依存しない結果を必要とする操作に特に役立ちます。

おそらく、PowerShellの設計者が、文字列との間で暗黙的に変換するときに不変のカルチャを一貫して使用するように動機付けたのは、カルチャ間の安定性です。

たとえば、日付文字列を'7/21/2017'スクリプトなどにハードコーディングし、後でキャストを使用して日付に変換しようとすると[date]、PowerShellのカルチャに依存しない動作により、米国以外のカルチャで実行してもスクリプトが壊れないようになります。 -英語が有効です-幸いなことに、不変のカルチャはISO8601形式の日付と時刻の文字列も認識します
たとえば、[datetime] '2017-07-21'うまくいきます。

反対に、現在の-culture-適切な文字列との間で変換する場合は、明示的に行う必要があります

要約する:

  • 文字列の変換

    • データ型のインスタンスをデフォルトでカルチャセンシティブな文字列表現で埋め込むと、カルチャ不変"..."の表現が生成されます(またはそのようなタイプの例です)。[double][datetime]
    • 現在のカルチャ表現を取得するには、.ToString()明示的に呼び出すか-f、フォーマット演算子を使用します(おそらく内部"..."で囲みを介して$(...))。
  • 文字列からの変換

    • 直接キャスト( )は、カルチャ不変の文字列表現[<type>] ...のみを認識します。

    • 現在のカルチャに適した文字列表現(または特定のカルチャの表現)から変換するには、ターゲットタイプの静的::Parse()メソッドを明示的に使用します(オプションで[cultureinfo]、特定のカルチャを表す明示的なインスタンスを使用します)。


文化-不変の例:

  • 文字列の補間キャスト

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

      • どちらも、現在のカルチャに関係なく、0.1小数点付きの文字列リテラルを生成します。.
    • 同様に、文字列からのキャストは文化に依存しません。例えば、[double] '1.2'

      • .現在の文化に関係なく、常に小数点として認識されます。
      • 別の言い方をすれば、デフォルトでは文化に敏感なメソッドのオーバーロードで[double] 1.2なく、文化に依存しないメソッドに変換されます。[double]::Parse('1.2') [double]::Parse('1.2', [cultureinfo]::InvariantCulture)
  • 文字列の比較(それが有効であると仮定し[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すると、文字列フォーマット演算子(上記のとおり):

    • [cultureinfo]::currentculture = 'de-DE'; '{0}' -f 1.2収量1,2
    • 落とし穴:演算子の優先順位により、RHSとしての式、そのように認識されるためにで -f囲む必要があります。(...)
      • たとえば、指定されている'{0}' -f 1/10かのように評価さ('{0}' -f 1) / 10れます。代わりに
        使用してください。'{0}' -f (1/10)
  • コンソールへのデフォルト出力:

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

    • 同じことがコマンドレットからの出力にも当てはまります。例:
      [cultureinfo]::CurrentCulture = 'de-DE'; Get-Date '2017-01-01'収量
      Sonntag, 1. Januar 2017 00:00:00

    • 警告:特定のシナリオでは、制約のないパラメーターとしてリテラルがスクリプトブロックに渡されると、カルチャに依存しないデフォルトの出力が生成される可能性があります。GitHubの問題#4557およびGitHubの問題#4558を参照してください。

  • /または//Set-ContentAdd-ContentOut-File>>>ファイル書き込む場合

    • 例:[cultureinfo]::CurrentCulture = 'de-DE'; 1.2 > tmp.txt; Get-Content tmp.txt収量1,2
  • ::Parse()::TryParse()[double]解析する文字列のみを渡す場合など、数値タイプでstatic /メソッドを使用する場合。たとえば、カルチャfr-FRが有効な場合(,は小数点マーク)、[double]::Parse('1,2')doubleを返します1.2(つまり、1 + 2/10)。

    • 警告bviktorが指摘しているように、デフォルトでは千単位の区切り文字が認識されますが、非常に緩い方法です。事実上、千単位の区切り文字は、結果のグループの桁数に関係なく、整数部分のどこ0にでも配置できます。また、受け入れられました。たとえば、en-USカルチャ(,千の区切り文字はどこにありますか)では、[double]::Parse('0,18')おそらく驚くほど成功し、を生成し18ます。
      • 数千の区切り文字の認識を抑制するには、パラメータ[double]::Parse('0,18', 'Float')を介して、のようなものを使用しますNumberStyles
  • 下位互換性を維持するために修正されない意図しない文化感度:

    • コンパイルされたコマンドレットのパラメーターバインディング型変換(ただし、PowerShellコード(スクリプトまたは関数)カルチャに依存しません)-GitHubの問題#6989を参照してください。
    • -asオペレーターの場合-GitHubの問題#8129を参照してください。
    • [hashtable]キールックアップでは、この回答GitHubの問題#8280を参照してください。
    • [ v7.1+で修正済み] 操作のLHSで-GitHubの-replace問題#10948を参照してください。
  • その他?

于 2016-06-02T23:29:59.417 に答える
11

これは、他のカルチャでスクリプトをテストするために使用する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
于 2010-03-04T15:04:28.683 に答える
5

私はそれを簡単にする方法を考えていて、アクセラレータを思いついた:

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

お役に立てば幸いです。

于 2010-03-04T14:40:11.393 に答える
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

もちろん、他のユーザーが異なるロケール設定でスクリプトを実行すると、意図したとおりの結果が得られない可能性があることに注意する必要があります。

それでも、このソリューションは役立つ可能性があります。楽しむ!

于 2017-02-24T10:35:51.810 に答える