- PR -

お手本になるようなソースコード

投稿者投稿内容
Anonymous Coward
会議室デビュー日: 2007/05/09
投稿数: 8
投稿日時: 2007-05-19 00:14
こんばんは。

そろそろ落ち着いてきたようですので、次のお題に移りたいと思います。

これだけスレの内容が高度化した後に、私の考えた低レベルなお題が、
果たして楽しんで頂けるかどうか不安なところではありますが、
お題が高度化してしまったために敷居が高くなってしまっている雰囲気もありますし、
思えば先のお題も最初はごく簡単なものであり、
その後皆さんの力でどんどん高度化していったことも事実ですので、
勇気を出して投稿してみたいと思います。

<お題>
CSVファイルを、TSVファイルに変換するプログラムを作ってください。
なお、CSVファイル及びTSVファイルの仕様は以下の通りとします。

・CSVファイルは、区切り文字にカンマを使用する。
・TSVファイルは、区切り文字にタブ文字を使用する。
・両ファイル共、行区切りには改行CRLFを使用する。
・両ファイル共、文字コードにはシフトJISを使用する。
・両ファイル共、クォート文字にダブルクォーテーションを使用する。
・データが区切り文字、クォート文字、改行のいずれかを含んでいた場合、両端をクォート文字で囲む。
・データ内のクォート文字は、2つ重ねることでエスケープする。
・データが区切り文字、クォート文字、改行のいずれも含まない場合、両端をクォート文字で囲まない。

文章だけで仕様がわかりずらい場合、Excelで保存したCSVファイルが
この形式になっていますので、参考にしてください。

なお、このお題は、前提条件によって難易度が変わってくると考えております。
<前提条件>
LV1:CSVデータは、カンマ、タブ、改行、ダブルクォーテーションのいずれも含まない。
LV2:CSVデータは、カンマとダブルクォーテーションを含む可能性があるが、タブと改行は含まない。
LV3:CSVデータは、カンマ、タブ、改行、ダブルクォーテーション全て含む可能性がある。


私がお題を考えると、経験上どうしても業務アプリ寄りのものになってしまいます。
スレ主しかお題を出してはいけないというルールはありませんので、
皆さんもおもしろいお題がありましたら、遠慮せずに出してください。
ただ、私としましては、複数の関連性の無いお題が並行で進む状況は、
なるべく避けたいと考えておりますので、
流れが落ち着いたタイミングを見計らって出題して頂けると嬉しいです。

それでは、よろしくお願い致します。
びしばし
大ベテラン
会議室デビュー日: 2002/03/13
投稿数: 181
投稿日時: 2007-05-21 12:21
えーと、.netのExcelクラスを使って、読んで書き出すだけ、じゃダメなんですか ?
「みんなでこの車輪を再発明するならどう書きます ?」という意図でしょうか。

...とこういうことを書く私ぐらいじゃないですか ? 「敷居が高い」人って。
引用:

お題が高度化してしまったために敷居が高くなってしまっている雰囲気もありますし、


お手本になるソースコードなら、コメントも正しい言葉を使いたいと思いませんか ?

[ メッセージ編集済み 編集者: びしばし 編集日時 2007-05-21 12:25 ]
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2007-05-21 14:06
引用:

びしばしさんの書き込み (2007-05-21 12:21) より:

えーと、.netのExcelクラスを使って、読んで書き出すだけ、じゃダメなんですか ? :)


".net の Excel クラス" とは何のことでしょうか?
標準の NCL にはそういったクラスは存在しませんので、Office PIA / VSTO のことでしょうか?

.NET ならば、TextFieldParser クラスで読み取って書き出しで良いと思いますが、
お題からすると、入出力を自前で書けということになると思います。

ただ仮にそうであったとして、"お手本になるコード" となると高パフォーマンスなコードを書くべきなのか、
それとも汎用的なクラスを書いて実装していくべきなのか、どちらなのかという疑問はありますね。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2007-05-21 14:34
引用:

とっちゃんさんの書き込み (2007-05-17 12:59) より:
C は、呼び出し時点より前に宣言(または定義)がある場合(前方参照)は、その宣言のとおりに、そうではない場合は、int func( ... )と仮定して呼び出します。(現行の Pure C でも通ります。がワーニングでると思いますw)。

C++は、このあいまいな定義を認めていないので、呼び出し時点より前に宣言も定義もなければ、エラーとして扱います。

JavaやC#などでは宣言(はそもそもない)や定義がどこにあってもよい事になっています。



指摘ありがとうございます。
最近あまり使っていないので私が勘違いしていたようですね。
ヘッダファイルが付く場合はそちらで宣言されるからOKなんでしたっけ?
とっちゃん
大ベテラン
会議室デビュー日: 2005/07/19
投稿数: 203
投稿日時: 2007-05-21 15:42
引用:

nagiseさんの書き込み (2007-05-21 14:34) より:

最近あまり使っていないので私が勘違いしていたようですね。
ヘッダファイルが付く場合はそちらで宣言されるからOKなんでしたっけ?


ヘッダーをあらかじめ呼び出し位置より前の行でインクルードしていればですがw
これを前方参照と言います。

Java や C# では、実質的な後方参照(ビルド中のソース行の時点で宣言が無いもの)が可能になっているのは、コンパイラの仕様がそうなっているからですね。

C++でも、クラスの宣言中にある関数の実装(C#やJavaみたいな書き方をした場合)は、後方参照の形になっていてもビルドが行えるようになっています。

ただし、自身を指す型以外は、前方参照が必須ですがw

_________________
// とっちゃん(高萩 俊行)@わんくま同盟
// とっちゃん’Blog
// MS-MVP for Developer Tools - Visual C++
// WindowsInstallerの話題はhttp://www.freeml.com/msiまで
マーサ
ベテラン
会議室デビュー日: 2004/11/26
投稿数: 87
投稿日時: 2007-05-22 14:27
引用:

Anonymous Cowardさんの書き込み (2007-05-19 00:14) より:

<お題>
CSVファイルを、TSVファイルに変換するプログラムを作ってください。



お疲れ様です。

何となくザット作ってみましたw
言語はJavaです。

チョット特殊な?作りになっていると思います^^;
こんなやり方もあるんだ〜的に見てくださいw

[追記]
出力ファイルは単純に”CSVファイル名.tsv”としています。。。

コード:

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.StringTokenizer;

/**
*
* カンマ区切りのファイルをタブ区切りに変換する。
*
* @author マーサ
* @version 1.0
*
*/
public class CsvConv {

/* 入力ファイル名 */
static String iFname = "";
/* 出力ファイル名 */
static String oFname = "";
/* 出力ファイル拡張子 */
static String FNAME_TSV = ".tsv";

/* カンマ */
static String STR_COMMA = ",";
/* タブ文字 */
static String STR_TAB = "\t";
/* タブ文字 */
static String STR_RETERN = "\r\n";

public static void main(String[] args) {
/* 入力ファイル名を指定しているか? */
if(args.length==1){
iFname = args[0];
}else{
System.out.println("Usage:java CsvConv FILEPATH");
return;
}

/* ファイルの存在チェック */
if(!chkFile(iFname)){
return;
}

oFname = iFname + FNAME_TSV;
try {
String line = "";
BufferedReader reader =
new BufferedReader( new FileReader(iFname) );
BufferedWriter writer =
new BufferedWriter( new FileWriter(oFname) );

/* 行単位に読み込み処理をする。 */
while(true) {
String buf = reader.readLine();
if(buf==null) break;

if(buf.length()==0){
/* 空行扱い */
writer.write(STR_RETERN);
}else{
line += buf;
/* 1行分のデータを読み込んだかチェック */
if(countQuotes(line)){
line += STR_RETERN;
writer.write(conv(line));
line = "";
}else{
/* クオート中の改行 */
line += STR_RETERN;
}
}
}
reader.close();
writer.close();
} catch(FileNotFoundException e) {
System.out.println("ファイルがありません");
} catch(IOException e) {
System.out.println("入出力エラーです");
}
}

/**
* 指定ファイルの妥当性チェック
*
* @param fPath ファイルパス
* @return 存在するファイルならtrue、それ以外はfalseを返す。
*
*/
public static boolean chkFile(String fPath) {
File file = new File(fPath);
/* ファイルある? */
if(!file.exists()){
System.out.println("["+fPath+"]ファイルがありません。");
return false;
}

/* それファイル? */
if(!file.isFile()){
System.out.println("["+fPath+"]はファイルではありません。");
return false;
}
return true;
}

/**
* 変換処理
*
* CSV(カンマ区切り)よりTSV(タブ区切り)に変換する。
*
* @param s 変換前行データ
* @return 変換後行データ
*/
public static String conv(String s) {
StringTokenizer st = new StringTokenizer(s,STR_COMMA);
String str = "";
String ans = "";
boolean flg = false;

do{
if(flg){
/* デリミタ設定 */
ans+= STR_TAB;
str = "";
}
str += st.nextToken();
/* 1区切り分変換したかチェック */
if(countQuotes(str)){
/* 1区切り分の変換終了 */
ans += str;
flg = true;
}else{
/* まだ未変換データ有り */
str += STR_COMMA;
flg = false;
}
}while(st.hasMoreTokens());

return ans;
}

/**
* 行解析
*
* クオート文字を元に、1Lineのデータであるかチェックする。
* CSVファイルのクオート文字は、基本的に偶数となるため、
* 単純に偶数/奇数チェックをしてみる。
*
* @param data 解析データ
* @return 1行のデータの場合true、それ以外はfalseを返す。
*/
public static boolean countQuotes(String data) {
int cnt = 0;

for(int i=0;i<data.length();i++){
if(data.charAt(i)=='\"'){
cnt++;
}
}

if((cnt%2)==0){
return true;
}else{
return false;
}
}
}



[ メッセージ編集済み 編集者: マーサ 編集日時 2007-05-22 14:42 ]
sawat
大ベテラン
会議室デビュー日: 2006/08/02
投稿数: 112
投稿日時: 2007-05-22 17:59
引用:

CSVファイルを、TSVファイルに変換するプログラムを作ってください。



では、JavaScriptで
コード:

function csv2tsv(csv) {
return csv.replace(/,([^",\r\n][^,\r\n]*|"([^"\r\n]|""|\r?\n)+")?/gm, "\t$1");
}



ファイルの入出力は端折って、変換部分のみですが。
JavaでもrepaceがrepaceAllになり、正規表現リテラルがないので見辛くなるだけでいっしょですね。

修正 投稿した内容の$1(ホントは半角)が消えるんですけど…

[ メッセージ編集済み 編集者: sawat 編集日時 2007-05-22 18:20 ]
sawat
大ベテラン
会議室デビュー日: 2006/08/02
投稿数: 112
投稿日時: 2007-05-22 19:32
さっきの間違ってた。各行の1カラム目がクォートされたカンマがあるとダメでした。
短くしようとしてバグを盛り込んでしまっては元も子もないですね

なので、訂正。
コード:

function csv2tsv(csv) {
var esc = [];
return csv.replace(/"(""|[^"])+"/g, function(m0){
esc.push(m0);
return '""';
}).replace(/,/g, "\t").replace(/""/g, function() {
return esc.shift();
});
}



Javaには移植しづらくなったし、お手本という観点からみても微妙

ちなみに入力に構文エラーがないことを前提にしてます。(お代に指示がなかったため)
エラーの例) "a",""a","a"

[ メッセージ編集済み 編集者: sawat 編集日時 2007-05-22 19:36 ]

追記:というかこれ全然仕様を満たしてないですね。思い違いをしてました。

[ メッセージ編集済み 編集者: sawat 編集日時 2007-05-23 14:19 ]

スキルアップ/キャリアアップ(JOB@IT)