如何使用 supercsv 仅跳过 white-space 行和具有可变列的行
How do I skip white-space only lines and lines having variable columns using supercsv
我正在处理 CSV 解析器需求,我正在使用 supercsv 解析器库。我的 CSV 文件可以有 25 列(由制表符 (|) 分隔)和最多 100k 行以及额外的 header 行。
我只想忽略 white-space 行和包含少于 25 列的行。
我正在使用带有名称映射(将 csv 值设置为 pojo)和字段处理器(以处理验证)的 IcvBeanReader 来读取文件。
我假设 Supercsv IcvBeanReader 默认会跳过白色 space 行。但是如果一行包含少于25个列号怎么处理?
(1) 如果选择必须由您的 Java 程序使用 Super CSV
完成,那么(我引用)"you'll have to use CsvListReader"。特别是:listReader.length()
(2) 如果您可以通过预处理 CSV 文件来执行选择,那么您可能希望考虑合适的 command-line 工具(或工具,取决于 CSV 格式的复杂程度)。如果 CSV 文件的分隔符没有出现在任何字段中,那么 awk 就足够了。例如,如果满足假设,并且分隔符是 |
,那么相关的 awk 过滤器可以像这样简单:
awk -F'|' 'NF == 25 {print}'
如果 CSV 文件格式对于 awk 的简单应用来说太复杂,那么您可能希望将复杂格式转换为更简单的格式;通常 TSV 有很多值得推荐的地方。
您可以通过编写自己的 Tokenizer 轻松地做到这一点。
例如,以下分词器将具有与默认分词器相同的行为,但会跳过任何列数不正确的行。
public class SkipBadColumnCountTokenizer extends Tokenizer {
private final int expectedColumns;
private final List<Integer> ignoredLines = new ArrayList<>();
public SkipBadColumnCountTokenizer(Reader reader,
CsvPreference preferences, int expectedColumns) {
super(reader, preferences);
this.expectedColumns = expectedColumns;
}
@Override
public boolean readColumns(List<String> columns) throws IOException {
boolean moreInputExists;
while ((moreInputExists = super.readColumns(columns)) &&
columns.size() != this.expectedColumns){
System.out.println(String.format("Ignoring line %s with %d columns: %s", getLineNumber(), columns.size(), getUntokenizedRow()));
ignoredLines.add(getLineNumber());
}
return moreInputExists;
}
public List<Integer> getIgnoredLines(){
return this.ignoredLines;
}
}
以及使用此 Tokenizer 的简单测试...
@Test
public void testInvalidRows() throws IOException {
String input = "column1,column2,column3\n" +
"has,three,columns\n" +
"only,two\n" +
"one\n" +
"three,columns,again\n" +
"one,too,many,columns";
CsvPreference preference = CsvPreference.EXCEL_PREFERENCE;
int expectedColumns = 3;
SkipBadColumnCountTokenizer tokenizer = new SkipBadColumnCountTokenizer(
new StringReader(input), preference, expectedColumns);
try (ICsvBeanReader beanReader = new CsvBeanReader(tokenizer, preference)) {
String[] header = beanReader.getHeader(true);
TestBean bean;
while ((bean = beanReader.read(TestBean.class, header)) != null){
System.out.println(bean);
}
System.out.println(String.format("Ignored lines: %s", tokenizer.getIgnoredLines()));
}
}
打印以下输出(注意它是如何跳过所有无效行的):
TestBean{column1='has', column2='three', column3='columns'}
Ignoring line 3 with 2 columns: only,two
Ignoring line 4 with 1 columns: one
TestBean{column1='three', column2='columns', column3='again'}
Ignoring line 6 with 4 columns: one,too,many,columns
Ignored lines: [3, 4, 6]
我正在处理 CSV 解析器需求,我正在使用 supercsv 解析器库。我的 CSV 文件可以有 25 列(由制表符 (|) 分隔)和最多 100k 行以及额外的 header 行。
我只想忽略 white-space 行和包含少于 25 列的行。
我正在使用带有名称映射(将 csv 值设置为 pojo)和字段处理器(以处理验证)的 IcvBeanReader 来读取文件。
我假设 Supercsv IcvBeanReader 默认会跳过白色 space 行。但是如果一行包含少于25个列号怎么处理?
(1) 如果选择必须由您的 Java 程序使用 Super CSV
完成,那么(我引用)"you'll have to use CsvListReader"。特别是:listReader.length()
(2) 如果您可以通过预处理 CSV 文件来执行选择,那么您可能希望考虑合适的 command-line 工具(或工具,取决于 CSV 格式的复杂程度)。如果 CSV 文件的分隔符没有出现在任何字段中,那么 awk 就足够了。例如,如果满足假设,并且分隔符是 |
,那么相关的 awk 过滤器可以像这样简单:
awk -F'|' 'NF == 25 {print}'
如果 CSV 文件格式对于 awk 的简单应用来说太复杂,那么您可能希望将复杂格式转换为更简单的格式;通常 TSV 有很多值得推荐的地方。
您可以通过编写自己的 Tokenizer 轻松地做到这一点。
例如,以下分词器将具有与默认分词器相同的行为,但会跳过任何列数不正确的行。
public class SkipBadColumnCountTokenizer extends Tokenizer {
private final int expectedColumns;
private final List<Integer> ignoredLines = new ArrayList<>();
public SkipBadColumnCountTokenizer(Reader reader,
CsvPreference preferences, int expectedColumns) {
super(reader, preferences);
this.expectedColumns = expectedColumns;
}
@Override
public boolean readColumns(List<String> columns) throws IOException {
boolean moreInputExists;
while ((moreInputExists = super.readColumns(columns)) &&
columns.size() != this.expectedColumns){
System.out.println(String.format("Ignoring line %s with %d columns: %s", getLineNumber(), columns.size(), getUntokenizedRow()));
ignoredLines.add(getLineNumber());
}
return moreInputExists;
}
public List<Integer> getIgnoredLines(){
return this.ignoredLines;
}
}
以及使用此 Tokenizer 的简单测试...
@Test
public void testInvalidRows() throws IOException {
String input = "column1,column2,column3\n" +
"has,three,columns\n" +
"only,two\n" +
"one\n" +
"three,columns,again\n" +
"one,too,many,columns";
CsvPreference preference = CsvPreference.EXCEL_PREFERENCE;
int expectedColumns = 3;
SkipBadColumnCountTokenizer tokenizer = new SkipBadColumnCountTokenizer(
new StringReader(input), preference, expectedColumns);
try (ICsvBeanReader beanReader = new CsvBeanReader(tokenizer, preference)) {
String[] header = beanReader.getHeader(true);
TestBean bean;
while ((bean = beanReader.read(TestBean.class, header)) != null){
System.out.println(bean);
}
System.out.println(String.format("Ignored lines: %s", tokenizer.getIgnoredLines()));
}
}
打印以下输出(注意它是如何跳过所有无效行的):
TestBean{column1='has', column2='three', column3='columns'}
Ignoring line 3 with 2 columns: only,two
Ignoring line 4 with 1 columns: one
TestBean{column1='three', column2='columns', column3='again'}
Ignoring line 6 with 4 columns: one,too,many,columns
Ignored lines: [3, 4, 6]