stuncloud / UWSCR

UWSC互換スクリプト実行ツール
MIT License
54 stars 5 forks source link

CSVファイルに"123"をFPUTするとファイル上には"""123"""と書かれている。 #201

Open DIYJii opened 3 months ago

DIYJii commented 3 months ago

概要

本題の通り。 EXCELで開くと "123", UWSCで開くと"""123""" と表示され、互換性の問題が生じています。 また現在、FPUTのCSVモードで、カラム単位でファイル上に "123" と書く手段は無く、全カラム・データをカンマで区切った 1行分のレコードとして書き込む方法しかありません。

一般に、CSVファイルの中には、ダブルクォーテーションで囲まれているか否かで,文字列と数値を区別する様式が有りますが、 その場合、前後のダブルクォーテーションの数は1つです。

再現スクリプト

f_Id =  FOPEN("TestFile.csv",  F_Read or F_Write)
FPUT(f_Id, "456",1,2) ; FPUT(f_Id ,"<#DBL>123<#DBL>",1,1)
FPUT(f_Id, "<#DBL>345<#DBL>,678",2)
                                                        //     UWSCR          //   UWSC
Print (FGET(f_Id,1,1) + "," + FGET(f_Id,1,2))           //    "123",456       //  123,456
Print (FGET(f_Id,2,1) + "," + FGET(f_Id,2,2))          //     345,678       //  345,678 

Print FGET(f_Id,1)                                      //"""123""",456       //"123",456  
Print FGET(f_Id,2)                                      //    "345",678       //"345",678 

MSGBOX("Ok ?")

再現手順

No response

回避方法

No response

備考

No response

バージョン

1.0.2

不具合発生環境

No response

stuncloud commented 3 months ago

原因

"123"を書き込む場合

  1. "が含まれるため、ダブルクォートで括る
  2. ""でエスケープする
  3. 結果"""123"""が書き込まれる

また、それを読み出した場合は

  1. ダブルクォートで括られているためその中を読み出す
  2. "がエスケープされている ("") ため"として扱う
  3. 結果"123"が読み出される

対策

原因欄にある通り"123"の書き込みおよび読み出しの動作としては正しいが、UWSCの仕様に原則合わせることとする とはいえ、UWSCの仕様だとデータとしてのダブルクォートを維持できないため、現行の書き込み方法も取れるように省略可能なオプション引数を追加する

// 実装例
fput(fid, '"abc"', 1, 1, TRUE)  // "abc" を書き込む (デフォルト)
fput(fid, '"abc"', 1, 1, FALSE) // """abc""" を書き込む (オプション、データとして " を保持できる)

UWSCの実装に合わせる懸念点として以下がある

// UWSC
fput(fid, "<#DBL><#DBL>123<#DBL><#DBL>", 1, 1)
fput(fid, "456", 1, 2)

とした場合にcsvファイルは以下の状態になり、これはCSVフォーマットとして不正であるため何かしらの対策が必要か

""123"",456

補足

@DIYJii CSVについての認識に誤りがあるようです

一般に、CSVファイルの中には、ダブルクォーテーションで囲まれているか否かで,文字列と数値を区別する様式が有りますが、

一般にそんな様式はありません (CSVの値はすべて文字列でありそれが数値かどうかの判断材料としてダブルクォートを使うということはないです) CSVフォーマットにおいてはメタ文字を含む場合にダブルクォートで括ることでそれらのメタ文字を有効なデータとすることができます

"123,456",""""
DIYJii commented 3 months ago

CSVフォーマットにおいてはメタ文字を含む場合にダブルクォートで括ることでそれらのメタ文字を有効なデータとすること ができます

最初の目的はそれだけだったのでしょうが、別に、他の目的で使ってはいけないという規則もないので、世間では、其れだ けではなく、項目をダブルコートで囲む事が普通に行われています。これは、例えば企業間のアプリのやり取りでCSVファイ ルが使われた場合、誤って数値扱いされてしまうと、郵便番号や電話番号の頭の0落ちをしてしまうので、それを防ぐ為にダ ブルクォートで文字である事を伝えるというのも、その理由の一つだったのだろうと思います。 ネットで「csvファイル ダブルクォート」等で検索してみると、それこそ5万と出てきます。

文字列と数値の区別については、下のサイトを見て下さい。

2分で分かる!CSVファイルの仕様と知っておきたいポイント

CSVの仕様を紐解く チェック項目      仕様             補足  項目を囲むダブルクォー 各項目の前後はダブルクォー  数値はダブルクォートで囲まず、文字列は テーション       テーションで囲んでも、     ダブルクォートで囲むというケースもあります。              囲まなくても良い

更に、以下にも 「csv.QUOTE_NONNUMERIC:数値でないフィールドにダブルクォーテーションを追加します。」 というのが有り、別にメタ文字だけの目的で使う訳ではないことを分って貰えると思います。

[Python]Pandasでダブルクォーテーションを操作する方法と実例

以下のオプションを使用することで、ダブルクォーテーションの挙動を制御することができます。 quotingパラメータ:ダブルクォーテーションの挙動を指定します。 以下の値を指定できます。 csv.QUOTE_ALL:すべてのフィールドにダブルクォーテーションを追加します。 csv.QUOTE_MINIMAL:特殊文字を含むフィールドのみにダブルクォーテーションを追加します。 csv.QUOTE_NONNUMERIC:数値でないフィールドにダブルクォーテーションを追加します。 csv.QUOTE_NONE:ダブルクォーテーションを追加しません。

本題に戻って、

3つのダブルクォートを1つにすれば解決する事なので述べなかったのですが、 今のUWSCRのままだと、もう一つの問題が残ります。

Print (FGET(f_Id,1,1) + "," + FGET(f_Id,1,2)) // "123",456

"123"だと、FGETの第4引数がDefaultのFalseの戻り値ではなく、Trueの状態の戻り値になっているのです。

UWSCのマニュアルより:

   ダブルコーテイション:    FALSE: 両端のダブルコーテイションは削除する (デフォルト)    TRUE: 削除しない

そして、第4引数をTRUEとすると

Print (FGET(f_Id,1,1,True)   // """123"""

となって、ユーザーにとっては自分が書いた覚えの無いものが出て来て、困ってしまう事になります。

stuncloud commented 3 months ago

@DIYJii

長々と反論をいただきましたが、あなたの言う数値はダブルクォートで括ず数字はダブルクォートで括るという運用をしたとしても、UWSCRはその区別を一切しないんですよ、UWSCもね そこは好きにしてください

そしてそこを好きにすることができるように、なるべくUWSC通りの実装もしますよ しかしUWSCがCSVを正しく扱っていないのは明らかなので現行仕様もオプションで残しますよ という話をしています

fgetの第四引数の話については動作に何も間違いはなく、それが正しい仕様です TRUEにすることでas-isで読み出す、FALSEならダブルクォートのエスケープを除いた本来の値を読み出す そしてその本来の値が"123"であるのだから、csvとしては"""123"""とエスケープされ記録されるわけで、TRUEで"""123"""、FALSEで"123"と読み出すのは何も問題ないでしょう (これが理解できなかったり、なにかしらの不満があったとしてもこれに関しての反論は勘弁してください、議論にもならず無駄すぎるので)

なんにしても現行仕様はオプションにしてデフォルトはUWSCに可能な限り合わせると言ってるんですから、あなたの問題は解決するはずです

stuncloud commented 3 months ago

Pandasの例が書かれてましたが、これを参考に定数による細かい制御ができてもいいかもしれませんね

UWSCはCSVとして不正な書き込みができてしまうが、これをフォローしつつなるべくUWSCの仕様を再現するのは現実的でなく、であればUWSCとの互換性は捨てるがユーザーが自由にCSVの読み書きができる方が利がありそう

そもそもfgetとfputにCSV機能を混ぜ込んでるのが間違いの元で、UWSCはこういう無茶実装が多すぎる

互換性を捨てる方向ならfcsvgetとfcsvputみたいに関数を分離してもいいかもしれない

stuncloud commented 3 months ago

実装方針を決めました

fput, fget

CSV専用関数を新設