- PR -

文字列の解析について

投稿者投稿内容
スフレ
ぬし
会議室デビュー日: 2005/05/27
投稿数: 281
お住まい・勤務地: 東京
投稿日時: 2007-11-19 14:53
製品に入れられるぐらいの品質でパーザ版を書いてみましたが、コーディング10分、行数で44行でした。
(コードは載せません)
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2007-11-19 15:30
では「¥」も「¥¥」で表現するのですね。
ちょっとしたパーサを書くなら、
BNFを書いてステートマシンで実装すれば意外と楽ですよ。
yamasa
ベテラン
会議室デビュー日: 2003/02/15
投稿数: 80
投稿日時: 2007-11-19 15:56
こんな感じかな。
コード:

String string = "A1=aaa,B1=bbb,C¥¥=1=c¥¥,cc";

Map<String, String> map = new LinkedHashMap<String, String>();
for (String item : string.split("(?<!¥¥¥¥),")) {
String[] pair = item.replace("¥¥,", ",").split("(?<!¥¥¥¥)=", 2);
if (pair.length < 2) {
System.err.println("パースエラー");
} else {
map.put(pair[0].replace("¥¥=", "="), pair[1].replace("¥¥=", "="));
}
}


ただし、¥自身のエスケープには対応していないので、
A1=aaa¥¥,B1=bbb

"A1"=>"aaa¥", "B1"=>"bbb"
ではなく
"A1"=>"aaa¥,B1=bbb"
となってしまいますが。

(文中の¥は全て半角に置き換えてください。)


[ メッセージ編集済み 編集者: yamasa 編集日時 2007-11-19 16:01 ]
Ray
ベテラン
会議室デビュー日: 2007/09/13
投稿数: 88
投稿日時: 2007-11-19 18:07
引用:

84さんの書き込み (2007-11-19 14:02) より:
<key>=<value>,<key>=<value>, ...
というのは、具体的には
key1=value1,key2=value2,key3=value3
のような文字列のことです。



正規表現をちょこっと変えればいい話では。
sawat
大ベテラン
会議室デビュー日: 2006/08/02
投稿数: 112
投稿日時: 2007-11-19 18:11
引用:

yamasaさんの書き込み (2007-11-19 15:56) より:
ただし、¥自身のエスケープには対応していないので、


否定後読みを使うのは僕も思いつきましたが、\自身のエスケープには
対応しづらいですね。

正規表現で\自身のエスケープも対応するなら、こんな感じかな。
コード:

public static Map<String, String> parse(final String string) {
String tokenPattern = "(?:[^\\\\,=]|\\\\[\\\\,=])+";
Pattern pair = Pattern.compile("(" + tokenPattern + ")=(" + tokenPattern + ")(?:,|$)");

Map<String, String> map = new HashMap<String, String>();
Matcher matcher = pair.matcher(string);
int index = 0;
while(matcher.find()) {
if(index != matcher.start()) throw new IllegalArgumentException("形式エラー");
index = matcher.end();
map.put(unescape(matcher.group(1)), unescape(matcher.group(2)));
}
return map;
}
private static String unescape(String string) {
return string.replaceAll("\\\\([\\\\,=])", "$1");
}



でも、これもunibonさんに言わせれば「トリッキー」になってしまうでしょうかね…。

編集
$1は$1に置換して下さい…

# プレビューで¥が増えたり、$[\d]が展開されたりとかいいかげん直して欲しい(--;

[ メッセージ編集済み 編集者: sawat 編集日時 2007-11-19 18:15 ]
84
ベテラン
会議室デビュー日: 2005/11/04
投稿数: 83
投稿日時: 2007-11-22 17:14
みなさまどうもありがとうございました。

正規表現の方法と
parserの方法とどちらも実装してみて
動作することを確認しました。

どちらを採用した方がいいのか
皆様の意見を参考にして、
もう一度よく考えてみようと思います。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2007-11-22 17:18
方式を選択する場合、特にどちらもバグがないのであれば、
ループで数十万回など実行して、
最短で終わる方を選択するとよいかと思います。
ranco
大ベテラン
会議室デビュー日: 2007/11/02
投稿数: 112
投稿日時: 2007-11-23 14:32
私もさんざん、split()メソッドと悪戦苦闘しました。これは、目的文字列そのものを正規表現で指定しないので、ぜったいできない課題もありますね。今回の課題は、前方参照(lookahead)を前でなく後ろに置くとか、後方参照(lookbehind)を後ろでなく前方に置くという、私の覚えたてホヤホヤの必殺わざ(今回はbehindのほう)でできますね。正規表現嫌いの人の顰蹙を買いそうですが。
--------------------------------------------------------------------
コード:
public class Splitter{


public static void main(String[] args){
String data
= "A1=aaa,B1=bbb,C\\=1=c\\,cc,D\\\\1=ddd,E1\\\\=eee\\\\,F1=fff";

String[] kvPairs = data.split("(?<!(?:\\\\(?<!\\\\\\\\)))[,=]");
for (int i = 0; i < kvPairs.length; i += 2){
System.out.print(kvPairs[i] + " = ");
System.out.println(kvPairs[i + 1]);
}
}
}


-------------------------------------------------------------------------
071124追記: むむむ、これも一般解ではないですね。エスケープされたバックスラッシュが複数個連続していると、エスケープされている,=を判別できない場合があります。エスケープされたバックスラッシュが連続していない場合用の解ということで、ごかんべんを(汗)。やっぱ、split()に多くを期待するのはだめだ!。

[ メッセージ編集済み 編集者: ranco 編集日時 2007-11-24 09:40 ]

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