背景
我需要解析 CSV 文件和cl-csv等。人。在大文件上速度太慢,并且依赖于cl-unicode,我首选的 lisp 实现不支持。所以,我正在改进cl-simple-table,Sabra-on-the-hill 在评论中将其作为最快的 csv 阅读器进行了基准测试。
目前,simple-table 的行解析器相当脆弱,如果分隔符出现在带引号的字符串中,它就会中断。我正在尝试用 cl-ppcre 替换行解析器。
尝试
使用 Regex Coach,我发现了一个几乎适用于所有情况的正则表达式:
("[^"]+"|[^,]+)(?:,\s*)?
挑战是把这个 Perl 正则表达式字符串变成我可以在 cl-ppcre 中使用的东西split
。我尝试传递正则表达式字符串,并为"
:
(defparameter bads "\"AER\",\"BenderlyZwick\",\"Benderly and Zwick Data: Inflation, Growth and Stock returns\",31,5,0,0,0,0,5,\"https://vincentarelbundock.github.io/Rdatasets/csv/AER/BenderlyZwick.csv\",\"https://vincentarelbundock.github.io/Rdatasets/doc/AER/BenderlyZwick.html\"
"Bad string, note a separator character in the quoted field, near Inflation")
(ppcre:split "(\"[^\"]+\"|[^,]+)(?:,\s*)?" bads)
NIL
单人、双人、三人或四人\
都不起作用。
我已经解析了字符串以查看解析树的样子:
(ppcre:parse-string "(\"[^\"]+\"|[^,]+)(?:,s*)?")
(:SEQUENCE (:REGISTER (:ALTERNATION (:SEQUENCE #\" (:GREEDY-REPETITION 1 NIL (:INVERTED-CHAR-CLASS #\")) #\") (:GREEDY-REPETITION 1 NIL (:INVERTED-CHAR-CLASS #\,)))) (:GREEDY-REPETITION 0 1 (:GROUP (:SEQUENCE #\, (:GREEDY-REPETITION 0 NIL #\s)))))
并将生成的树传递给split
:
(ppcre:split '(:SEQUENCE (:REGISTER (:ALTERNATION (:SEQUENCE #\" (:GREEDY-REPETITION 1 NIL (:INVERTED-CHAR-CLASS #\")) #\") (:GREEDY-REPETITION 1 NIL (:INVERTED-CHAR-CLASS #\,)))) (:GREEDY-REPETITION 0 1 (:GROUP (:SEQUENCE #\, (:GREEDY-REPETITION 0 NIL #\s))))) bads)
NIL
我还尝试了各种形式*allow-quoting*
:
(let ((ppcre:*allow-quoting* t))
(ppcre:split "(\\Q\"\\E[^\\Q\"\\E]+\\Q\"\\E|[^,]+)(?:,\s*)?" bads))
我已经阅读了cl-ppcre 文档,但是使用解析树的例子很少,也没有转义引号的例子。
似乎没有任何效果。
我希望 Regex Coach 能够提供一种查看 Perl 语法字符串的 S 表达式解析树形式的方法。这将是一个非常有用的功能,允许您试验正则表达式字符串,然后将解析树复制并粘贴到 Lisp 代码中。
有谁知道如何在这个例子中转义引号?