Mencoba:
public class Main {
public static void main(String[] args) {
String line = "foo,bar,c;qual=\"baz,blurb\",d;junk=\"quux,syzygy\"";
String[] tokens = line.split(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", -1);
for(String t : tokens) {
System.out.println("> "+t);
}
}
}
Keluaran:
> foo
> bar
> c;qual="baz,blurb"
> d;junk="quux,syzygy"
Dengan kata lain: pisahkan pada koma hanya jika koma itu memiliki nol, atau bahkan jumlah kutipan di depannya .
Atau, sedikit lebih ramah untuk mata:
public class Main {
public static void main(String[] args) {
String line = "foo,bar,c;qual=\"baz,blurb\",d;junk=\"quux,syzygy\"";
String otherThanQuote = " [^\"] ";
String quotedString = String.format(" \" %s* \" ", otherThanQuote);
String regex = String.format("(?x) "+ // enable comments, ignore white spaces
", "+ // match a comma
"(?= "+ // start positive look ahead
" (?: "+ // start non-capturing group 1
" %s* "+ // match 'otherThanQuote' zero or more times
" %s "+ // match 'quotedString'
" )* "+ // end group 1 and repeat it zero or more times
" %s* "+ // match 'otherThanQuote'
" $ "+ // match the end of the string
") ", // stop positive look ahead
otherThanQuote, quotedString, otherThanQuote);
String[] tokens = line.split(regex, -1);
for(String t : tokens) {
System.out.println("> "+t);
}
}
}
yang menghasilkan sama dengan contoh pertama.
EDIT
Seperti yang disebutkan oleh @MikeFHay dalam komentar:
Saya lebih suka menggunakan Splitter Guava , karena memiliki default lebih waras (lihat diskusi di atas tentang pertandingan kosong yang dipangkas String#split()
, jadi saya lakukan:
Splitter.on(Pattern.compile(",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"))
String line = "equals: =,\"quote: \"\"\",\"comma: ,\""
, semua yang perlu Anda lakukan adalah menghapus tanda kutip ganda yang asing karakter.-1
ke perpecahan metode param:line.split(regex, -1)
. Lihat: docs.oracle.com/javase/6/docs/api/java/lang/…Splitter.on(Pattern.compile(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)"))
.findAllIn("(?s)(?:\".*?\"|[^\",]*)*")
dalam kombinasi dengan langkah postprocessing untuk melewati bidang pertama (selalu kosong) mengikuti setiap bidang yang tidak kosong.Walaupun saya menyukai ekspresi reguler pada umumnya, untuk jenis tokenisasi yang bergantung pada keadaan ini, saya percaya parser sederhana (yang dalam hal ini jauh lebih sederhana daripada kata yang membuatnya terdengar) mungkin merupakan solusi yang lebih bersih, khususnya yang berkaitan dengan pemeliharaan , misalnya:
Jika Anda tidak peduli tentang menjaga koma di dalam tanda kutip, Anda dapat menyederhanakan pendekatan ini (tidak ada penanganan indeks awal, tidak ada huruf khusus karakter terakhir ) dengan mengganti koma Anda dalam tanda kutip dengan sesuatu yang lain dan kemudian membaginya dengan tanda koma:
sumber
http://sourceforge.net/projects/javacsv/
https://github.com/pupi1985/JavaCSV-Reloaded (garpu dari perpustakaan sebelumnya yang akan memungkinkan output yang dihasilkan memiliki terminator jalur Windows
\r\n
ketika tidak menjalankan Windows)http://opencsv.sourceforge.net/
API CSV untuk Java
Bisakah Anda merekomendasikan perpustakaan Java untuk membaca (dan mungkin menulis) file CSV?
Lib Java atau aplikasi untuk mengkonversi file CSV ke XML?
sumber
Saya tidak akan menyarankan jawaban regex dari Bart, saya menemukan solusi parsing lebih baik dalam kasus khusus ini (seperti yang diusulkan Fabian). Saya telah mencoba solusi regex dan implementasi parsing sendiri. Saya telah menemukan bahwa:
Solusi dan tes saya di bawah ini.
Tentu saja Anda bebas untuk beralih ke lain-jika dalam potongan ini jika Anda merasa tidak nyaman dengan kejelekannya. Perhatikan kemudian kurangnya istirahat setelah beralih dengan pemisah. StringBuilder dipilih sebagai ganti untuk StringBuffer dengan desain untuk meningkatkan kecepatan, di mana keamanan benang tidak relevan.
sumber
-1
metode split pada jawaban Bart, Anda akan menangkap string kosong (termasuk string kosong setelah koma terakhir):line.split(regex, -1)
Coba lookaround seperti
(?!\"),(?!\")
. Ini harus cocok dengan,
yang tidak dikelilingi oleh"
.sumber
(?<!"),(?!")
, tetapi itu masih tidak akan berhasil. Diberikan stringone,two,"three,four"
, itu dengan benar cocok dengan komaone,two
, tetapi juga cocok dengan koma"three,four"
, dan gagal mencocokkan satu dengantwo,"three
.Anda berada di area perbatasan yang menjengkelkan di mana regexps hampir tidak akan melakukan (seperti yang telah ditunjukkan oleh Bart, lolos dari kutipan akan membuat hidup jadi sulit), namun parser besar tampaknya seperti terlalu banyak pembunuhan.
Jika Anda cenderung membutuhkan kompleksitas yang lebih besar dalam waktu dekat, saya akan mencari parser library. Misalnya yang ini
sumber
Saya tidak sabar dan memilih untuk tidak menunggu jawaban ... untuk referensi itu tidak terlihat sulit untuk melakukan hal seperti ini (yang berfungsi untuk aplikasi saya, saya tidak perlu khawatir tentang pelolosan kutipan, seperti hal-hal dalam tanda kutip terbatas pada beberapa bentuk terbatas):
(latihan untuk pembaca: memperluas penanganan kutipan lolos dengan mencari backslash juga.)
sumber
Pendekatan yang paling sederhana adalah tidak mencocokkan pembatas, yaitu koma, dengan logika tambahan yang kompleks untuk mencocokkan apa yang sebenarnya dimaksudkan (data yang mungkin dikutip string), hanya untuk mengecualikan pembatas palsu, melainkan mencocokkan data yang dimaksud di tempat pertama.
Pola terdiri dari dua alternatif, string yang dikutip (
"[^"]*"
atau".*?"
) atau semuanya hingga koma berikutnya ([^,]+
). Untuk mendukung sel kosong, kami harus mengizinkan item yang tidak dikutip menjadi kosong dan menggunakan koma berikutnya, jika ada, dan menggunakan\\G
jangkar:Pola ini juga berisi dua grup penangkap untuk mendapatkan, konten string yang dikutip atau konten biasa.
Kemudian, dengan Java 9, kita bisa mendapatkan array sebagai
sedangkan versi Java yang lebih lama membutuhkan loop seperti
Menambahkan item ke
List
atau array dibiarkan sebagai cukai untuk pembaca.Untuk Java 8, Anda dapat menggunakan
results()
implementasi dari jawaban ini , untuk melakukannya seperti solusi Java 9.Untuk konten campuran dengan string yang disematkan, seperti dalam pertanyaan, Anda dapat menggunakannya
Tapi kemudian, string disimpan dalam bentuk yang dikutip.
sumber
Daripada menggunakan lookahead dan regex gila lainnya, cukup tarik keluar tanda kutip terlebih dahulu. Yaitu, untuk setiap pengelompokan kutipan, ganti pengelompokan itu dengan
__IDENTIFIER_1
atau beberapa indikator lainnya, dan petakan peta itu ke peta string, string.Setelah Anda pisah pada koma, ganti semua pengidentifikasi yang dipetakan dengan nilai string asli.
sumber
bagaimana dengan one-liner menggunakan String.split ()?
sumber
Saya akan melakukan sesuatu seperti ini:
sumber