2011-03-10 94 views
3

例字符串:如何構建正則表達式來解析逗號分隔值,但忽略雙引號中的逗號?

2011-03-09,4919 1281 0410 9930,55107,SAZB2314,"John, Doe" ,1-888-888-4452 ext 1813 

需要標記所有的逗號而不是雙引號中的一個。

+9

請勿使用正則表達式。不要使用正則表達式。不要使用正則表達式。使用文本解析器。 – CanSpice 2011-03-10 20:01:49

+0

但文本解析器不使用正則表達式將輸入分解爲令牌嗎? – shawnhcorey 2016-12-22 13:08:52

+0

如果你想學習,不要使用文本解析器。 如果您想提高生產力,請不要使用正則表達式。 – 2017-11-09 00:27:29

回答

0

如果你需要一個正則表達式,而不是像@eugene這樣的正確解析器,那麼這裏是一個嘗試。捕獲應該按順序返回列表元素。

(?:(?:([^"]*?|".*?"),)*([^"]*?|".*?"))? 
10

或使用Text::CSV_XS,它做同樣的事情,但速度更快。

+2

由於Text :: CSV導致文本:: CSV_XS被使用(如果可用),它不一定更快。儘管如此,我建議使用Text :: CSV_XS,因爲它消除了使用Text :: CSv的額外複雜性,並保證Text :: CSV_X通過較慢的Text :: CSV_PP獲得Text :: CSV_XS。 – ikegami 2011-03-10 21:22:24

0

嘗試:

use strict; 
use warnings; 
use Text::ParseWords; 

while (<DATA>) { 
    chomp; 
    my @f = quotewords ',', 0, $_; 
    for (@f) { 
      s/^\s*|\s*$//g; 
      s/^/"/ && s/$/"/ if /,/; 
    } 
    print join (",", @f), "\n"; 
} 

__DATA__ 
2011-03-09,4919 1281 0410 9930,55107,SAZB2314,"John, Doe" ,1-888-888-4452 ext 1813 
"ashish", "kumar", "test,1", "test2" 
"foo", "b,ar", "msg1", "msg2" 
-1

我知道如何在Java中做到這一點。正則表達式在PERL中可能會有所不同,但讓我展示這個想法。有3個子句的聯合。

// 1) select any quoted text before comma 
// if it fails then 
// 2) select any text before comma 
// if it also fails then 
// 3) select any text before end of the input 

final String OR   = "|"; 
final String QUOTE  = "\"[\\s]*"; //with trailing whitespaces 
final String NON_QUOTES = "[^\"]*"; 
final String COMMA  = ","; 
final String NON_COMMA = "[^,]*"; 
final String NON_END  = "[^$]+"; 
final String END   = "$"; 

final Pattern p = Pattern.compile(
QUOTE+NON_QUOTES+QUOTE+COMMA+ 
OR+ 
NON_COMMA+COMMA+ 
OR+ 
NON_END+END); 

它會給你比賽,不幸的是會以逗號結束,除了最後一個。沒有捕獲組,因爲用像這樣的union子句來定義它們是沒有意義的。

+1

類似於Regexp :: Grammars,Parser :: MGC或Parse :: RecDescent將是創建等同於此的Perl代碼的方式。但對於CSV,已經有模塊可以解決這個問題。 – MkV 2012-08-20 13:37:09

0

我目前正在研究一個項目,這個正則表達式幫助我以完全相同的格式創建一個csv文件。

("([^"]*)",?)|(([^",]*),?)

如果一個記錄被隨機分成多行這將無法正常工作。我有這個問題,並通過確定非空匹配的計數是否正確來解決它。

相關問題