2009-03-10 40 views
32

No estoy muy seguro de si esto es posible, así que me dirijo a usted.Regex para elegir comas fuera de las comillas

Me gustaría encontrar una expresión regular que seleccione todas las comas que caen fuera de los conjuntos de comillas.

Por ejemplo:

'foo' => 'bar', 
'foofoo' => 'bar,bar' 

Esto sería escoger el sola coma en la línea 1, después de 'bar',

Realmente no importa sola vs comillas dobles.

¿Alguien tiene alguna idea? Siento que esto debería ser posible con Readaheads, pero mi expresión regular es demasiado débil.

+3

Respuesta final oficial, dada por MarkusQ: (,) (? = (?: [^ "'] | [" |'] [^ "'] *") * $) – SocialCensus

+0

Como nota, esto no funciona a través de saltos de línea de cita intermedia. – SocialCensus

+0

@SocialCensus vea mi nota adjunta a la respuesta. – MarkusQ

Respuesta

74

Esto hará coincidir cualquier cadena hasta e incluyendo el primer "," no citado. ¿Es eso lo que quieres?

/^([^"]|"[^"]*")*?(,)/ 

Si desea que todos ellos (y como un contraejemplo con el tipo que dijo que no era posible) se podría escribir:

/(,)(?=(?:[^"]|"[^"]*")*$)/ 

que coincidirá con todos ellos. Por lo tanto

'test, a "comma,", bob, ",sam,",here'.gsub(/(,)(?=(?:[^"]|"[^"]*")*$)/,';') 

reemplaza todas las comas no cotizaciones interiores con punto y coma, y ​​produce:

'test; a "comma,"; bob; ",sam,";here' 

Si lo necesita para trabajar a través de saltos de línea sólo tiene que añadir la bandera (multilínea) m.

+0

Parece que funciona correctamente, con comillas dobles. (,) (? = (?: [^ "'] | [" |'] [^ "'] *") * $) Creo que funciona con comillas simples O comillas dobles. ¡Gracias! – SocialCensus

+1

Quería señalar que esto no funciona en todos los saltos de línea. – SocialCensus

+0

@SocialCensus Luego usa la bandera m. Además, su ejemplo en el comentario anterior tiene varios errores. Por ejemplo, toma comillas dobles, comillas simples y barras verticales como comillas de apertura, pero solo toma comillas dobles como comillas de cierre. – MarkusQ

1

Pruebe esta expresión regular:

(?:"(?:[^\\"]+|\\(?:\\\\)*[\\"])*"|'(?:[^\\']+|\\(?:\\\\)*[\\'])*')\s*=>\s*(?:"(?:[^\\"]+|\\(?:\\\\)*[\\"])*"|'(?:[^\\']+|\\(?:\\\\)*[\\'])*')\s*, 

Esto también permite que cadenas como “'foo\'bar' => 'bar\\',”.

+0

Éste no parece funcionar para mí ... – SocialCensus

1

La respuesta de MarkusQ funcionó muy bien para mí durante aproximadamente un año, hasta que no lo hizo. Acabo de recibir un error de desbordamiento de pila en una línea con aproximadamente 120 comas y 3682 caracteres en total. En Java, así:

 String[] cells = line.split("[\t,](?=(?:[^\"]|\"[^\"]*\")*$)", -1); 

Aquí está mi reemplazo muy poco elegante que no desbordamiento de pila:

private String[] extractCellsFromLine(String line) { 
    List<String> cellList = new ArrayList<String>(); 
    while (true) { 
     String[] firstCellAndRest; 
     if (line.startsWith("\"")) { 
      firstCellAndRest = line.split("([\t,])(?=(?:[^\"]|\"[^\"]*\")*$)", 2); 
     } 
     else { 
      firstCellAndRest = line.split("[\t,]", 2);     
     } 
     cellList.add(firstCellAndRest[0]); 
     if (firstCellAndRest.length == 1) { 
      break; 
     } 
     line = firstCellAndRest[1]; 
    } 
    return cellList.toArray(new String[cellList.size()]); 
} 
1

@SocialCensus, el ejemplo que dio en el comentario a MarkusQ, donde se lanza en ' junto con el ", no funciona con el ejemplo MarkusQ dado arriba que si cambiamos sam a sam: (prueba, una" coma ", bob,", sam's, ", aquí) no tiene rival contra (,) (? = (?: [^ "'] | [" |'] [^ "'] ") $). De hecho, el problema tself, "Realmente no me importan las comillas simples versus las dobles", es ambiguo. Tiene que tener claro lo que quiere decir con una cita con "o con". Por ejemplo, ¿está permitido anidar o no? De ser así, ¿a cuántos niveles? Si solo 1 nivel anidado, ¿qué sucede con una coma fuera de la cita anidada interna? pero dentro de la cita externa de anidación también debería considerar que las comillas simples ocurren por sí mismas como apóstrofes (es decir, como el contraejemplo que di antes con sam).Finalmente, la expresión regular que usted creó realmente no trata las comillas simples a la par con comillas dobles ya que asume que el último tipo de comillas es necesariamente una comilla doble, y reemplazar la última comilla doble con ['| "] también tiene un problema si el texto no viene con las citas correctas (o si se usan apóstrofes), supongo que probablemente podríamos suponer que todas las comillas están delineadas correctamente.

La respuesta regular de MarkusQ responde a la pregunta: encuentre todas las comas que tengan un número par de comillas dobles después de esto (es decir, están fuera de comillas dobles) y descartar todas las comas que tienen un número impar de comillas dobles después (es decir, están entre comillas dobles). Esta es generalmente la misma solución que probablemente desee, pero vamos a observe algunas anomalías. Primero, si alguien deja una comilla al final, esta expresión busca todas las comas incorrectas en lugar de encontrar las deseadas o no hacer coincidir ninguno. Por supuesto, si falta una comilla doble, todas las apuestas están desactivadas ya que puede no estar claro si la que falta pertenece al final o en su lugar pertenece al principio; sin embargo, hay un caso que es legítimo y donde la expresión regular podría fallar (esta es la segunda "anomalía"). Si ajusta la expresión regular para recorrer las líneas de texto, debe tener en cuenta que al citar varios párrafos consecutivos es necesario que coloque una comilla doble al principio de cada párrafo y omita la cita al final de cada párrafo, excepto en el fin del último párrafo. Esto significa que en el espacio de esos párrafos, la expresión regular fallará en algunos lugares y tendrá éxito en otros.

Ejemplos y breves discusiones de citas de párrafos y de citas anidadas se pueden encontrar aquí http://en.wikipedia.org/wiki/Quotation_mark.

+4

Esto no responde a la pregunta. Para criticar o solicitar aclaración de un autor, deje un comentario debajo de su publicación. – mattt

+0

Tengo que echar otro vistazo a este problema, pero me di cuenta de que mi "respuesta" era bastante larga. ¿Encajaría eso como un comentario? También, mi respuesta anterior parece responder que no hay necesariamente una única respuesta correcta debido a las ambigüedades en la pregunta (di ejemplos). Probablemente pensé que esta respuesta/crítica iba más allá de un comentario al autor y agrega un contexto a aquellos que buscan una respuesta. edite la pregunta o ¿tendré que depender de alguien más? [necesito profundizar en este tema que plantea cuando encuentro el momento] –

+0

@mattt did no significa que parece ignorar su solicitud. Tengo poco tiempo ahora. –

6

las siguientes expresiones regulares se compararán todos los de la coma que están presentes fuera de las comillas dobles,

,(?=(?:[^"]*"[^"]*")*[^"]*$) 

DEMO

O (PCRE solamente)

"[^"]*"(*SKIP)(*F)|, 

"[^"]*" partidos todo el bloque citado doble Es decir, en esta entrada buz,"bar,foo", esta expresión regular solo coincidiría con "bar,foo". Ahora, la siguiente (*SKIP)(*F) hace que la coincidencia falle. Luego pasa al patrón que estaba junto al símbolo | e intenta hacer coincidir los caracteres de la cadena restante. Es decir, en nuestra salida , junto al patrón | coincidirá solo con la coma que estaba justo después de buz. Tenga en cuenta que esto no coincidirá con la coma que estaba presente entre comillas dobles, porque ya hacemos que la parte con comillas dobles se salte.

DEMO


La continuación de expresiones regulares se correspondería con todo de la coma que están presentes dentro de las comillas dobles,

,(?!(?:[^"]*"[^"]*")*[^"]*$) 

DEMO

2

Si bien es posible entrar ilegalmente en él con una expresión regular (y disfruto abusando de expresiones regulares tanto como el siguiente tipo), te meterás en problemas, tarde o temprano, tratando de manejar subcadenas sin más analizador avanzado Las posibles formas de meterse en problemas incluyen comillas mixtas y citas escapadas.

Esta función dividirá una cadena en comas, pero no esas comas que están dentro de una cadena de una o dos comillas.Se puede ampliar fácilmente con caracteres adicionales para usar como cotizaciones (aunque los pares de caracteres como «» necesitarían unas cuantas líneas de código) y incluso le dirá si se olvidó de cerrar una cita en sus datos:

function splitNotStrings(str){ 
    var parse=[], inString=false, escape=0, end=0 

    for(var i=0, c; c=str[i]; i++){ // looping over the characters in str 
    if(c==='\\'){ escape^=1; continue} // 1 when odd number of consecutive \ 
    if(c===','){ 
     if(!inString){ 
     parse.push(str.slice(end, i)) 
     end=i+1 
     } 
    } 
    else if(splitNotStrings.quotes.indexOf(c)>-1 && !escape){ 
     if(c===inString) inString=false 
     else if(!inString) inString=c 
    } 
    escape=0 
    } 
    // now we finished parsing, strings should be closed 
    if(inString) throw SyntaxError('expected matching '+inString) 
    if(end<i) parse.push(str.slice(end, i)) 
    return parse 
} 

splitNotStrings.quotes="'\"" // add other (symmetrical) quotes here 
Cuestiones relacionadas