8

たくさんの浮動小数点数を含むファイルを読まなければならないとしましょう。数値は1e+105-0.15など、つまり、小数点を使用した任意の一般的な浮動小数点数にすることができます (これは固定されています! )。ただし、私のコードは別のアプリケーションのプラグインであり、現在のロケールを制御することはできません。たとえば、ロシア語である可能性があり、そこでの LC_NUMERIC 規則では、使用する小数点のカンマが必要です。したがって、Pi は「3,1415...」と綴られると予想されます。

sscanf("3.14", "%f", &x); 

「1」を返し、「.」以降の解析を拒否するため、x には「3.0」が含まれます。文字列で。

このような数値解析タスクでは、ロケールを無視する必要があります。

どうやってそれを行うのですか?

parseFloat 関数を書くこともできましたが、これはもったいないようです。
また、現在のロケールを保存し、一時的に「C」にリセットし、ファイルを読み取り、保存されたものに復元することもできました。これのパフォーマンスへの影響は何ですか?一部の OS/libc コンボでは setlocale() が非常に遅くなる可能性があります。
さらに別の方法として iostream を使用することもできますが、やはりパフォーマンスは優れたものではありません。

だから私は困惑しています。そんな時、皆さんはどうしていますか?

乾杯!

4

3 に答える 3

7

私の個人的な好みは、 を使用しないことLC_NUMERICです。つまり、単にsetlocale他のカテゴリで呼び出すか、 で呼び出した後に をsetlocale使用しLC_ALLますsetlocale(LC_NUMERIC, "C");。そうしないと、標準ライブラリを使用して数値を標準形式で印刷または解析して交換したい場合、完全に運が悪くなります。

幸運にも POSIX 2008 準拠のシステムを使用している場合は、uselocaleおよび*_l関数ファミリーを使用して状況をいくらか改善することができます。少なくとも 2 つの基本的なアプローチがあります。

  1. デフォルトのロケールを未設定のままにし (少なくともLC_NUMERIC;のような厄介な部分LC_CTYPEはおそらく常にlocale_t設定する必要があります)、ユーザーのロケールのオブジェクトを適切な*_l関数に渡します。期待; それ以外の場合は、デフォルトの C ロケールを使用します。

  2. 交換のためにデータを操作する必要があるコードでは、C ロケールのオブジェクトを保持し、交換のために標準形式でデータを操作する必要がある場合はlocale_t、前後に切り替えるか、適切な関数を使用します (ただし、いいえ)。uselocale*_lscanf_l

独自の浮動小数点パーサーを実装するのは簡単ではなく、数値計算の専門家でない限り、おそらく問題の適切な解決策ではないことに注意してください。それを正しくすることは非常に難しいです。

于 2012-12-17T18:32:08.227 に答える
3

これが私が過去にこのものでやったことです。

目標は、C ロケールの数値表現でロケール依存の数値コンバーターを使用することです。もちろん、理想は、ロケールに依存しないコンバーターを使用するか、ロケールを変更しないことです。ロケールのサポートはいくつかの点で深刻に壊れており、これはその 1 つです。</rant>

Cまず、数値前処理トークンの文法の単純なパターンのようなものを使用して、数値を文字列として抽出します。scanf で使用するために、さらに単純なものを実行します。

" %1[-+0-9.]%[-+0-9A-Za-z.]"

入力ストリームで他に何を期待するかによって、これはさらに単純化できます。あなたがする必要がある唯一のことは、数字の終わりを超えて読まないことです。数字の直後に空白を入れずに文字が続くことを許可しない限り、上記は問題なく機能します。

次に、を使用して現在のロケールを表すstruct lconv( ) を取得します。その構造体の最初のエントリは; 文字列内のすべての文字をその値に置き換えます。(ほとんどのロケールでは変更されず、構造体の符号フィールドは通貨変換にのみ適用されると記載されていますが、文字と文字も置き換える必要がある場合があります。) 最後に、結果の文字列をフィードして、それが通過するかどうかを確認します。man 7 localelocaleconv(3)const char* decimal_point'.''+''-'lconvstrtod

これは完全なアルゴリズムではありません。特に、特定のライブラリが実際にどの程度ロケールに準拠しているかを知るのは必ずしも容易ではないため、実際にコンパイルしているライブラリ用に構成するために autoconf を実行する必要がある場合があります。

于 2012-12-17T20:11:59.063 に答える
3

Cでそれを解決する方法がわかりません。

しかし、C++ ストリームは一意のロケール オブジェクトを持つことができます。

std::stringstream  dataStream;
dataStream.imbue(std::locale("C"));

// Note: You must imbue the stream before you do anything wit it.
//       If any operations have been performed then an imbue() can
//       be silently ignored by the stream (which is a pain to debug).

dataStream << "3.14";
float   x;
dataStream >> x;
于 2012-12-17T19:16:51.437 に答える