私はフォーマットが付属していCSV持っている:引用符を持つことになり、解析CSVは
のみフィールドと
A6A1、A2、A3、 "A4、A5" を、
Javaを使用すると、これを簡単に解析する方法は?私は会社のポリシーとしてオープンソースのCSVパーサーを使用しないようにしています。ありがとう。
私はフォーマットが付属していCSV持っている:引用符を持つことになり、解析CSVは
のみフィールドと
A6A1、A2、A3、 "A4、A5" を、
Javaを使用すると、これを簡単に解析する方法は?私は会社のポリシーとしてオープンソースのCSVパーサーを使用しないようにしています。ありがとう。
あなたは次の正規表現でMatcher.find
を使用することができます。ここでは、より完全な例です
\s*("[^"]*"|[^,]*)\s*
:
String s = "a1, a2, a3, \"a4,a5\", a6";
Pattern pattern = Pattern.compile("\\s*(\"[^\"]*\"|[^,]*)\\s*");
Matcher matcher = pattern.matcher(s);
while (matcher.find()) {
System.out.println(matcher.group(1));
}
は、それがオンラインで作業を参照してください:ideone
私はこの同じ問題に出くわしました(でもPythonで)、正規表現なしでそれを解決する方法の1つが見つかりました: あなたが行を取得したら、 reは引用符で、引用符で文字列を分割し、得られた配列のインデックス付きの結果をカンマで分割します。奇数のインデックス付き文字列は、引用符で囲まれた完全な値である必要があります。
私はJavaのコーダよんので、擬似コードとしてこれを取る...
またline = String[];
if ('"' in row){
vals = row.split('"');
for (int i =0; i<vals.length();i+=2){
line+=vals[i].split(',');
}
for (int j=1; j<vals.length();j+=2){
line+=vals[j];
}
}
else{
line = row.split(',')
}
、正規表現を使用します。
ここにいくつかのコードがありますが、私はここからコードを使用してオープンソースをカウントしないことを願っています。
package bestsss.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class SplitCSVLine {
public static String[] splitCSV(BufferedReader reader) throws IOException{
return splitCSV(reader, null, ',', '"');
}
/**
*
* @param reader - some line enabled reader, we lazy
* @param expectedColumns - convenient int[1] to return the expected
* @param separator - the C(omma) SV (or alternative like semi-colon)
* @param quote - double quote char ('"') or alternative
* @return String[] containing the field
* @throws IOException
*/
public static String[] splitCSV(BufferedReader reader, int[] expectedColumns, char separator, char quote) throws IOException{
final List<String> tokens = new ArrayList<String>(expectedColumns==null?8:expectedColumns[0]);
final StringBuilder sb = new StringBuilder(24);
for(boolean quoted=false;;sb.append('\n')) {//lazy, we do not preserve the original new line, but meh
final String line = reader.readLine();
if (line==null)
break;
for (int i = 0, len= line.length(); i < len; i++) {
final char c = line.charAt(i);
if (c == quote) {
if(quoted && i<len-1 && line.charAt(i+1) == quote){//2xdouble quote in quoted
sb.append(c);
i++;//skip it
}else{
if (quoted){
//next symbol must be either separator or eol according to RFC 4180
if (i==len-1 || line.charAt(i+1) == separator){
quoted = false;
continue;
}
} else{//not quoted
if (sb.length()==0){//at the very start
quoted=true;
continue;
}
}
//if fall here, bogus, just add the quote and move on; or throw exception if you like to
/*
5. Each field may or may not be enclosed in double quotes (however
some programs, such as Microsoft Excel, do not use double quotes
at all). If fields are not enclosed with double quotes, then
double quotes may not appear inside the fields.
*/
sb.append(c);
}
} else if (c == separator && !quoted) {
tokens.add(sb.toString());
sb.setLength(0);
} else {
sb.append(c);
}
}
if (!quoted)
break;
}
tokens.add(sb.toString());//add last
if (expectedColumns !=null)
expectedColumns[0] = tokens.size();
return tokens.toArray(new String[tokens.size()]);
}
public static void main(String[] args) throws Throwable{
java.io.StringReader r = new java.io.StringReader("222,\"\"\"zzzz\", abc\"\" , 111 ,\"1\n2\n3\n\"");
System.out.println(java.util.Arrays.toString(splitCSV(new BufferedReader(r))));
}
}
以下のコードはうまくいくようで、引用符で囲むことができます。
final static Pattern quote = Pattern.compile("^\\s*\"((?:[^\"]|(?:\"\"))*?)\"\\s*,");
public static List<String> parseCsv(String line) throws Exception
{
List<String> list = new ArrayList<String>();
line += ",";
for (int x = 0; x < line.length(); x++)
{
String s = line.substring(x);
if (s.trim().startsWith("\""))
{
Matcher m = quote.matcher(s);
if (!m.find())
throw new Exception("CSV is malformed");
list.add(m.group(1).replace("\"\"", "\""));
x += m.end() - 1;
}
else
{
int y = s.indexOf(",");
if (y == -1)
throw new Exception("CSV is malformed");
list.add(s.substring(0, y));
x += y;
}
}
return list;
}
簡単にはわかりませんが、CSVにはいくつかの偽のエッジケースがあります。エスケープされた引用符 - いくつかのスタイルを使用します。フィールド値の改行 - 発生したCSV行でエラーを報告する必要がある場合は面白いです。既存のパーサーを使用できず、これらを処理する必要がある場合は、パーサーを作成します。 (パーザジェネレータが許可されていないと、楽しいことです) – millimoose
会社がオープンソースのlibs {ライセンスに関係なく}を要求していて、簡単な構文解析で助けが必要な場合... – bestsss
@Inerdia、解析は、手書きコードの約30行であり、ジェネレータが不要です。 – bestsss