Regex per raccogliere virgole al di fuori delle virgolette

Non sono sicuro che sia ansible, quindi mi rivolgo a te.

Mi piacerebbe trovare una regex che selezionerà tutte le virgole che non rientrano nei set di virgolette.

Per esempio:

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

Questo avrebbe scelto la singola virgola sulla linea 1, dopo 'bar',

Non mi interessa davvero le virgolette singole o doppie.

Qualcuno ha qualche idea? Credo che questo dovrebbe essere ansible con i readaheads, ma il mio regex fu troppo debole.

Questo corrisponderà a qualsiasi stringa fino a includere il primo non quotato “,”. E ‘quello che stai volendo?

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

Se li vuoi tutti (e come contro-esempio per il ragazzo che ha detto che non è ansible) potresti scrivere:

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

che corrisponderà a tutti loro. così

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

sostituisce tutte le virgole non all’interno di virgolette con punto e virgola e produce:

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

Se ne hai bisogno per lavorare su interruzioni di linea basta aggiungere il m (multiline) flag.

Le regex di seguito corrisponderanno a tutte le virgole che sono presenti al di fuori delle virgolette doppie,

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

DEMO

OPPURE (solo PCRE)

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

"[^"]*" corrisponde a tutto il doppio blocco quotato, cioè in questo buz,"bar,foo" input buz,"bar,foo" , questa regex corrisponderebbe solo a "bar,foo" . Ora il seguente (*SKIP)(*F) fa fallire la corrispondenza, quindi passa al pattern che era accanto a | symbol e cerca di far corrispondere i caratteri della stringa rimanente. Cioè, nel nostro output , accanto a pattern | corrisponderà solo alla virgola che era appena dopo Si noti che questo non corrisponderà alla virgola che era presente tra virgolette, perché già facciamo saltare la parte doppia citazione.

DEMO


La regex di seguito corrisponderebbe a tutte le virgole che sono presenti all’interno delle virgolette doppie,

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

DEMO

Mentre è ansible hackerarlo con una regex (e mi diverto ad abusare delle regex tanto quanto il prossimo), ti troverai nei guai prima o poi proverai a gestire le sottostringhe senza un parser più avanzato. I modi possibili per mettersi nei guai includono citazioni misti e citazioni sfuggite.

Questa funzione dividerà una stringa su virgole, ma non quelle che si trovano all’interno di una stringa singola o doppia. Può essere facilmente esteso con caratteri aggiuntivi da usare come virgolette (anche se coppie di caratteri come «» richiederebbero qualche riga in più di codice) e ti diranno anche se hai dimenticato di chiudere un preventivo nei tuoi dati:

 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 

Prova questa espressione regolare:

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

Ciò consente anche stringhe come ” 'foo\'bar' => 'bar\\', “.

La risposta di MarkusQ ha funzionato benissimo per me per circa un anno, fino a quando non è stato così. Ho appena ricevuto un errore di overflow di stack su una riga con circa 120 virgole e 3682 caratteri in totale. In Java, come questo:

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

Ecco la mia sostituzione estremamente inelegante che non impila overflow:

 private String[] extractCellsFromLine(String line) { List cellList = new ArrayList(); 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()]); } 

@SocialCensus, L’esempio che hai fornito nel commento a MarkusQ, dove inserisci “accanto a”, non funziona con l’esempio che MarkusQ ha dato sopra, se cambiamo sam in sam : (test, una “virgola”, bob, “, sam’s,”, qui) non ha corrispondenza con (,) (? = (?: [^ “‘] | [” |’] [^ “‘] “) $). In effetti, il problema stesso “Non mi interessa davvero le virgolette singole o doppie”, è ambiguo: devi essere chiaro cosa intendi citando “o con”. Ad esempio, il nesting è consentito o no? Se sì, a quanti livelli? Se solo 1 livello annidato, cosa succede a una virgola al di fuori dell’offerta interna annidata ma all’interno dell’offerta di annidamento esterna? Dovresti anche considerare che le virgolette singole accadono da sole come apostrofi (cioè, come il contro-esempio che ho dato in precedenza con Sam’s). Infine, la regex che hai fatto non considera le virgolette singole alla pari con virgolette doppie poiché presuppone che l’ultimo tipo di virgolette sia necessariamente una virgoletta doppia – e anche la sostituzione dell’ultima virgoletta con [‘| “] ha un problema se il testo non viene fornito con virgolette corrette (o se vengono usati gli apostrofi), suppongo che probabilmente potremmo assumere che tutte le virgolette siano delineate correttamente.

L’espressione regolare di MarkusQ risponde alla domanda: trova tutte le virgole che hanno un numero pari di virgolette doppie (cioè, sono al di fuori delle virgolette doppie) e ignorano tutte le virgole che hanno un numero dispari di virgolette doppie (cioè, sono racchiuse tra virgolette doppie). Questa è generalmente la stessa soluzione di quello che probabilmente vorresti, ma guardiamo alcune anomalie. Per prima cosa, se qualcuno lascia una virgoletta alla fine, allora questa espressione regolare trova tutte le virgole sbagliate piuttosto che trovare quelle desiderate o non riuscire a eguagliarle. Ovviamente, se manca una virgoletta doppia, tutte le scommesse sono off poiché potrebbe non essere chiaro se quello mancante appartiene alla fine o invece appartiene all’inizio; tuttavia, esiste un caso legittimo e in cui la regex potrebbe fallire (questa è la seconda “anomalia”). Se modifichi l’espressione regolare per passare attraverso le righe di testo, allora dovresti sapere che la citazione di più paragrafi consecutivi richiede che tu inserisca una virgoletta singola all’inizio di ogni paragrafo e che lasci la citazione alla fine di ogni paragrafo eccetto che per fine dell’ultimo paragrafo. Ciò significa che nello spazio di quei paragrafi, la regex fallirà in alcuni punti e avrà successo in altri.

Esempi e brevi discussioni sulla quotazione di paragrafi e di quotazioni annidate sono disponibili qui http://en.wikipedia.org/wiki/Quotation_mark .