CSVファイルでエスケープされていない二重引用符を見つけるための正規表現
質問
CSVファイル内の二重引用符で区切られた列に含まれる2つのエスケープされていない二重引用符のセットを見つけるための正規表現はどうなりますか?
一致しない:
"asdf","asdf"
"", "asdf"
"asdf", ""
"adsf", "", "asdf"
一致:
"asdf""asdf", "asdf"
"asdf", """asdf"""
"asdf", """"
解決
これを試してください:
(?m)""(?![ \t]*(,|$))
説明:
(?m) // enable multi-line matching (^ will act as the start of the line and $ will act as the end of the line (i))
"" // match two successive double quotes
(?! // start negative look ahead
[ \t]* // zero or more spaces or tabs
( // open group 1
, // match a comma
| // OR
$ // the end of the line or string
) // close group 1
) // stop negative look ahead
したがって、平易な英語では:" 2つの連続する二重引用符に一致します。ただし、それらの前にコンマまたは行末がなく、オプションでスペースとタブが間にある場合のみです; strong>。
(i)通常の文字列の開始および文字列の終了メタ文字であることに加えて。
他のヒント
問題は複雑であるため、解決策は使用しているエンジンによって異なります。これを解決するには、後ろを見て先を見る必要があり、各エンジンはこれと同じではないためです。
私の答えは、Rubyエンジンを使用することです。チェックはRegExの1つにすぎませんが、より良い説明のためにコード全体をここに記載しています。
注:Ruby RegExエンジン(または私の知識)により、オプションの先読み/後読みは不可能です。したがって、コンマの前後にスペースの小さな問題が必要です。
ここに私のコードがあります:
orgTexts = [
'"asdf","asdf"',
'"", "asdf"',
'"asdf", ""',
'"adsf", "", "asdf"',
'"asdf""asdf", "asdf"',
'"asdf", """asdf"""',
'"asdf", """"'
]
orgTexts.each{|orgText|
# Preprocessing - Eliminate spaces before and after comma
# Here is needed if you may have spaces before and after a valid comma
orgText = orgText.gsub(Regexp.new('\" *, *\"'), '","')
# Detect valid character (non-quote and valid quote)
resText = orgText.gsub(Regexp.new('([^\"]|^\"|\"$|(?<=,)\"|\"(?=,)|(?<=\\\\)\")'), '-')
# resText = orgText.gsub(Regexp.new('([^\"]|(^|(?<=,)|(?<=\\\\))\"|\"($|(?=,)))'), '-')
# [^\"] ===> A non qoute
# | ===> or
# ^\" ===> beginning quot
# | ===> or
# \"$ ===> endding quot
# | ===> or
# (?<=,)\" ===> quot just after comma
# \"(?=,) ===> quot just before comma
# (?<=\\\\)\" ===> escaped quot
# This part is to show the invalid non-escaped quots
print orgText
print resText.gsub(Regexp.new('"'), '^')
# This part is to determine if there is non-escaped quotes
# Here is the actual matching, use this one if you don't want to know which quote is un-escaped
isMatch = ((orgText =~ /^([^\"]|^\"|\"$|(?<=,)\"|\"(?=,)|(?<=\\\\)\")*$/) != 0).to_s
# Basicall, it match it from start to end (^...$) there is only a valid character
print orgText + ": " + isMatch
print
print ""
print ""
}
実行すると、コードが印刷されます:
"asdf","asdf"
-------------
"asdf","asdf": false
"","asdf"
---------
"","asdf": false
"asdf",""
---------
"asdf","": false
"adsf","","asdf"
----------------
"adsf","","asdf": false
"asdf""asdf","asdf"
-----^^------------
"asdf""asdf","asdf": true
"asdf","""asdf"""
--------^^----^^-
"asdf","""asdf""": true
"asdf",""""
--------^^-
"asdf","""": true
ここで、他のエンジンや言語で使用できるアイデアをお伝えしたいと思います。
".*"(\n|(".*",)*)
動作するはずです...
単一行の一致の場合:
^("[^"]*"\s*,\s*)*"[^"]*""[^"]*"
または複数行の場合:
(^|\r\n)("[^\r\n"]*"\s*,\s*)*"[^\r\n"]*""[^\r\n"]*"
編集/注:使用されている正規表現エンジンに応じて、lookbehindsなどを使用して正規表現をよりスリムにすることができます。しかし、これはほとんどの正規表現エンジンで問題なく動作するはずです。
この正規表現を試してください:
"(?:[^",\\]*|\\.)*(?:""(?:[^",\\]*|\\.)*)+"
これは、引用符で囲まれた文字列と、エスケープされていない二重引用符のペアが少なくとも1つ一致するものです。