我目前正在編寫一個csv解析器。 csv格式的定義由由ABNF定義的RFC4180給出。所以csv的定義絕對是一個無競爭的語法。但是,我想知道csv是否是正則語法?這樣我就可以用一個有限狀態機來解析它。此外,如果它恰好是一個正則語法,並且可以用有限狀態機進行分析,那麼這是否意味着它也可以通過正則表達式進行分析?csv格式是正則語法還是上下文無關語法?
回答
我沒有任何正式的理論可以驗證這一點,但我很確定CSV文件可以可靠地使用正則表達式進行分析。這可能是最好使用兩個正則表達式,但:
- 一個正則表達式匹配整個CSV行(包括引號的字段換行符)
- 另一個正則表達式(要在第一個比賽結果使用)配單場
(除非你使用.NET正則表達式引擎可用於訪問重複捕獲組的單獨捕獲,或者除非你知道你的CSV文件中的列數和事先硬代碼到你的正則表達式)。
一個PCRE正則表達式匹配整個CSV行可能是:
/^(?:(?:[^",\r\n]*|"(?:""|[^"]*)*+")(?:,|$))*+(?=$)/m
這裏需要使用/m
修改,以允許^
和$
匹配換行符。如果你正在逐行處理文件,那麼正則表達式在一個不是完整的CSV行的行上將會失敗(例如,引用的字段尚未關閉),所以你需要讀取下一行,add將其添加到您的測試字符串並重新應用正則表達式(您可以在此方案中刪除/m
修飾符)。重複,直到匹配。
一旦你的行中,你可以使用這個正則表達式來每個連續字段相匹配:
/([^",\r\n]*|"(?:""|[^"]*)*+")(?:,|$)/
的比賽結果在這裏還包含了分隔符(,
或換行),因此實際的字段的內容必須被提取從第1組開始。在比賽結束後,您還需要處理周圍和嵌入的引號。
說明:
^ # Start of line (/m modifier!)
(?: # Start of non-capturing group (to contain the entire line):
(?: # Start of non-capturing group (to contain a single field):
[^",\r\n]* # Either match a run of character except quotes, commas or newlines
| # or
" # Match a quoted field, starting with a quote, followed by
(?: # either...
"" # an escaped quote
| # or
[^"]* # anything that's not a quote
)*+ # repeated as often as possible, no backtracking allowed
" # Then match a closing quote
) # End of group (=field)
(?:,|$) # Match a delimiter or the end of the line
)*+ # repeated as often as possible, no backtracking allowed
(?=$) # Assert that we're now at the end of a line
語言確實很規律。但我真的不建議用正則表達式解析它。簡單的解析器通常更快,更易於調試。 – Joey
關於'(?= $)':'$'已經是一個零寬度的斷言,所以你不需要通過將它貼在一個lookahead中來「斷言」它。 –
沒有明確回答這個問題,因爲CSV是一個非常鬆散的格式。我觀察到的CSV閱讀器中都保留了上下文無關和常規語法。例如,一些讀者在封閉值結束後會拋出一個異常,除非逗號出現。
那麼,有各種各樣的CSV的變化,但有一個真正的RFC:http://tools.ietf.org/html/rfc4180 –
@Bart - 該RFC是一個微妙的嘗試來記錄的格式,大部分它基於假設。 –
是的,我現在剛注意到文檔中的*「它沒有指定任何類型的Internet標準」*。 –
您應該可以使用簡單的有限狀態機來解析CSV文件。或者,更確切地說,根據精確的CSV格式,使用大量簡單的FSM中的一種。 (這並不意味着這是一個好主意,還有一些CSV解析庫,它可以更好地處理所有奇怪的變體以及您可能會發現的不成文的CSV文件規則。)
這裏有沒有一些(未經測試)柔性規則良好的錯誤處理的最簡單的CSV變:
領域與分離,
空白是不以任何方式特殊的,除了未分類記錄的換行符外
字段包括「,,或換行符必須加引號;任何領域都可能被引用。
一個「在引用字段被表示爲兩個」字符。
%%
int record = 1;
int field = 1;
[^",\n]*/[^"] { printf("Record %d Field %d: |%s|\n", record, field, yytext); }
[,] { ++field; }
[\n] { ++line; field = 1; }
["]([^"]|["]["]*)["]/[,\n] {
printf("Record %d Field %d: |%s|\n", record, field, yytext); }
. { printf("Something bad happened in record %d field %d\n",
record, field); }
不能處理正常引用的字符串(即,它不剝去引號或undouble加倍引號)。
處理引述領域的最簡單的方法是使用一個啓動條件(這仍然是作爲一個有限狀態機的部分實現):
%x QUOTED
%%
int record = 1;
int field = 1;
[^",\n]*/[^"] { printf("Record %d Field %d: |%s|\n", record, field, yytext); }
[,] { ++field; }
[\n] { ++line; field = 1; }
["] { printf("Record %d Field %d: |", record, field); BEGIN(QUOTED); }
<QUOTED>[^"]* { printf("%s", yytext); }
<QUOTED>["]["] { putchar('"'); }
<QUOTED>["]/[,\n] { putchar('|'); putchar('\n'); BEGIN(INITIAL); }
<*>. { printf("Something bad happened in record %d field %d\n",
record, field); }
- 1. 上下文無關語法
- 2. 這兩個上下文無關語法規則是否相同?
- 3. 上下文無關語法公式
- 4. 上下文無關語法與上下文敏感語法?
- 5. 正式上下文無關文法從上下文無關語言
- 6. 上下文無關文法語法
- 7. 算法從任何正則表達式生成上下文無關語法
- 8. 上下文無關語法的算法
- 9. 用於表示正則表達式的上下文無關語法
- 10. 查找上下文無關語法(CFG)
- 11. 「任意」上下文無關語法?
- 12. 上下文無關語法幫助
- 13. 將EBNF語法轉換爲上下文無關語法
- 14. 上下文無關語法是否可以左右遞歸?
- 15. 這些上下文無關語法是否等價?
- 16. 什麼是模棱兩可的上下文無關語法?
- 17. 順序是否在上下文無關語法中起作用?
- 18. 如何檢查一個上下文無關語法的語言是否是第二個上下文無關語法的子集?
- 19. 是否有任何不是上下文無關語言的正規語言?
- 20. Vim的語法文件是關於HTML語法嚴格
- 21. 爲以下語言編寫上下文無關語法
- 22. 無論給定上下文無關語言是正規
- 23. 這是什麼語法?上下文無關的或上下文敏感的
- 24. 英語是否有正式的語法?
- 25. 這個上下文無關文法是一個正則表達式嗎?
- 26. React中的語法語法有效還是無效?
- 27. 描述正則表達式的上下文無關文法?
- 28. 正則表達式語法
- 29. 爲語言創建上下文無關語法
- 30. 語言的上下文無關語法的數量多於bs
NIT採摘澄清你的條件的位:「如果CSV是正規文法」 :csv文件是語言的一個語句(字母表中所有可能的字符串的子集)。無論您是使用解析器還是可以脫離FSA,都取決於您爲此語言編寫的語法。如果你寫的語法是規則的,那麼你對FSA很好(這是最快的方法),如果你的語法沒有上下文,你需要一個解析器。順便說一下,REs只是一種編寫常規語法的形式:您可以使用常規生產系統來描述RG,但是您必須驗證應用FSM的規則性。 – user1666959
@ user1666959謝謝。現在我明白了「這取決於你寫什麼語法」。然而,我認爲在這種情況下我想知道的是「什麼是最低的文法可以用來解析csv」。現在我認爲這個「最低語法」是正規語法。 – n3v3rm03