【问题标题】:Read csv that is not well written读取写得不好的csv
【发布时间】:2015-02-20 07:00:00
【问题描述】:

我的 csv 写得不好:

标题是:

"xxx"|"yyy"|"zzz"|"nnn"|"...."

所以我尝试创建一个扫描仪并在管道上拆分:

Scanner scanner   = new Scanner(new File("myCsv.csv"));
int first = 1;
String line;
String row[];
while(scanner.hasNextLine()){
   line = scanner.nextLine();
   row  = line.split("\\|");
   if(first==1){
    first = 0;
    continue;
   }
   ...
}

不幸的是,在 csv 的一列中我发现了一个新行,因此“nextLine”不是获取整行的好方法。

另一个问题是管道存在于列内..类似于:

"field1"|"field|2"|"field3\n"|"..."

所以我认为解析该 csv 的最佳方法是创建一个匹配 ".."|".." 字符串的正则表达式模式。

有人可以帮助我吗?

谢谢!

【问题讨论】:

  • 如何在引号内指定"
  • 对我来说,| 分隔 CSV 看起来写得很好。
  • 如果您查看 "field1"|"field|2"|"field3\n"|"..." 并拆分为管道,它将字段和 2 拆分为两个字段而不是一个字段
  • 我的意思是,当字段包含" 时,CSV 是什么样的?
  • 你为什么说这个文件写得不好,你为什么不找一个存在的csv库呢?

标签: java regex csv


【解决方案1】:

因为您的 csv 不包含任何转义的双引号,我建议您进行匹配而不是拆分。

"(?s)\".*?\""

(?s) 称为 dotall 修饰符,它使您的模式中的点匹配偶数换行符。

DEMO

String s = "\"xxx\"|\"yyy|bar\"|\"zzz\"|\"nn\n" + 
        "n\"|\"....\"";
Matcher m = Pattern.compile("(?s)\".*?\"").matcher(s);
while(m.find())
{
        System.out.println(m.group(0));
}

输出:

"xxx"
"yyy|bar"
"zzz"
"nn
n"
"...."

如果您不想在最终输出中出现双引号,请使用捕获组。

String s = "\"xxx\"|\"yyy|bar\"|\"zzz\"|\"nn\n" + 
        "n\"|\"....\"";
Matcher m = Pattern.compile("(?s)\"(.*?)\"").matcher(s);
    while(m.find())
    {
        System.out.println(m.group(1));
    }

输出:

xxx
yyy|bar
zzz
nn
n
....

【讨论】:

    【解决方案2】:
    \|(?=(?:[^"]*"[^"]*")*[^"]*$)
    

    您可以使用它来拆分您的字符串。参见演示。

    https://regex101.com/r/vN3sH3/48

    【讨论】:

      【解决方案3】:

      为自己选择一个已经存在的CSV Library,它将为您处理此问题和其他问题。 CSV 不像“逗号分隔”那么简单,所以没有必要重新发明轮子

      【讨论】:

      • 您确定它适用于这种情况,其中字段可以在引号内包含未转义的换行符吗?
      • 我没有使用过那个特定的库,因为它是一个 Apache 项目,所以我猜它正确地符合 CSV 规范
      【解决方案4】:

      刚刚使用此正则表达式 ["][|]["] 进行了简单的字符串拆分测试。

      所以你可以使用你的代码:row = line.split("[\"][|][\"]");

      或者我的测试用一个简单的字符串拆分:

      public static void main(String[] args) {
          String text = "\"xxx\"|\"yyy\"|\"zzz\"|\"nnn\"|\"....\"";
          String regex = "[\"][|][\"]";
      
          String[] textArray= text.split(regex);
          for(String part:textArray){
              System.out.println(part);
          }        
      }
      

      这将输出:

      "xxx
      yyy
      zzz
      nnn
      ...."
      

      因此,只需删除开头和结尾的 " 即可获得拆分字符串。

      You can also test any regex on regex test websites.

      【讨论】:

      • 列内换行怎么样?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多