首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

正則表達式解析 CSV 含引號欄位:原理與侷限性說明

     編輯:程式設計綜合問答

題目正則

var result = Regex.Split("1,2,3,\"4,5,7,8\",6,\"7\"\"8\"", 
    @"(?<!""(\d+,)*\d+),(?!\d+(,\d+)*"")");

運作原理

此正則使用零寬度斷言 (Lookaround) 實現「不分隔引號內的逗號」:

  • (?<!""(\d+,)*\d+) — 負向後顧斷言:確保逗號左側 不是 「雙引號 + 純數字欄位 (含內部逗號)」。
  • (?!\d+(,\d+)*"") — 負向前顧斷言:確保逗號右側 不是 「純數字欄位 + 雙引號」。
  • 兩者結合,僅在「非引號包裹的數字欄位之間」的逗號處分割。

關鍵侷限

  1. 僅支援純數字欄位:斷言內硬編碼 \d+,若欄位含字母 (如 "a,b,c") 即失效。
  2. 不處理巢狀/跳脫引號:範例中 \"7\"\"8\" 代表欄位值 7"8 (CSV 標準雙引號跳脫),此正則無法正確解析。
  3. 效能風險:可變寬度後顧斷言在某些引擎 (如 JavaScript) 不支援;.NET 支援但長字串回溯慢。

健壯替代方案:有限狀態機 (FSM) 掃描

參考同系列文章 (ID 36554) 的狀態機實作:normal / inquote 兩狀態,單趟掃描字元,遇引號切換狀態,逗號僅在 normal 狀態分割。可正確處理:

  • 任意字元欄位 (含中文、特殊符號)
  • 雙引號跳脫 ("" → ")
  • 多行欄位 (含換行符)
  • 效能 O(n)、無回溯、記憶體恆定

程式碼片段 (C# 簡化版)

public static IEnumerable ParseCsvLine(string line) {
    var field = new StringBuilder();
    bool inQuote = false;
    for (int i = 0; i < line.Length; i++) {
        char c = line[i];
        if (c == '"') {
            if (inQuote && i + 1 < line.Length && line[i+1] == '"') {
                field.Append('"'); i++; // 跳脫雙引號
            } else {
                inQuote = !inQuote; // 進入/離開引號區塊
            }
        } else if (c == ',' && !inQuote) {
            yield return field.ToString();
            field.Clear();
        } else {
            field.Append(c);
        }
    }
    yield return field.ToString(); // 最後一欄
}

總結

正則雖短但脆弱,CSV 解析請務必用狀態機或成熟庫 (如 CsvHelper、TextFieldParser),避免邊界情況導致資料損壞。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved