Expresión regular para encontrar comillas dobles sin escape en el archivo CSV

StackOverflow https://stackoverflow.com/questions/1601780

  •  05-07-2019
  •  | 
  •  

Pregunta

¿Cuál sería una expresión regular para encontrar conjuntos de 2 comillas dobles sin escape que están contenidas en columnas separadas por comillas dobles en un archivo CSV?

No es una coincidencia:

"asdf","asdf"
"", "asdf"
"asdf", ""
"adsf", "", "asdf"

Match:

"asdf""asdf", "asdf"
"asdf", """asdf"""
"asdf", """"
¿Fue útil?

Solución

Prueba esto:

(?m)""(?![ \t]*(,|$))

Explicación:

(?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

Entonces, en inglés simple: " combina dos comillas dobles sucesivas, solo si NO tienen una coma o el final de la línea delante de ellas con espacios y tabulaciones opcionales entre " .

(i) además de ser los meta caracteres normales inicio de cadena y fin de cadena .

Otros consejos

Debido a la complejidad de su problema, la solución depende del motor que esté utilizando. Esto se debe a que para resolverlo, debe mirar atrás y mirar hacia adelante y cada motor no es el mismo.

Mi respuesta es usar el motor Ruby. La comprobación es solo un RegEx, pero eliminé todo el código aquí para explicarlo mejor.

TENGA EN CUENTA que, debido al motor Ruby RegEx (o mi conocimiento), no es posible mirar hacia adelante / atrás opcional. Entonces necesito un pequeño problema de espacios antes y después de la coma.

Aquí está mi código:

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 ""
} 

Cuando se ejecuta el código se imprime:

"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

Espero que te de una idea que puedas usar con otro motor e idioma.

".*"(\n|(".*",)*)

debería funcionar, supongo ...

Para coincidencias de una sola línea:

^("[^"]*"\s*,\s*)*"[^"]*""[^"]*"

o para líneas múltiples:

(^|\r\n)("[^\r\n"]*"\s*,\s*)*"[^\r\n"]*""[^\r\n"]*"

Editar / Nota: Dependiendo del motor de expresión regular utilizado, puede usar look behinds y otras cosas para hacer que la expresión regular sea más ágil. Pero esto debería funcionar bien en la mayoría de los motores de expresiones regulares.

Pruebe esta expresión regular:

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

Eso coincidirá con cualquier cadena entre comillas con al menos un par de comillas dobles sin escape.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top