Domanda

Ok, ho una stringa multilinea su cui sto cercando di fare un po 'di pulizia.

Ogni riga può essere o meno parte di un grande blocco di testo tra virgolette. Esempio:

This line is not quoted.
This part of the line is not quoted “but this is.”
This one is not quoted either.
“This entire line is quoted”
Not quoted.
“This line is quoted
and so is this one
and so is this one.”
This is not quoted “but this is
and so is this.”

Ho bisogno di un sostituto RegEx che disimballerà le righe tra virgolette, ovvero sostituirà " \ r \ n " con uno spazio, ma solo tra le virgolette.

Ecco come dovrebbe essere sostituita la sostituzione:

This line is not quoted.
This part of the line is not quoted “but this is.”
This one is not quoted either.
“This entire line is quoted”
Not quoted.
“This line is quoted and so is this one and so is this one.”
This is not quoted “but this is and so is this.”

(Nota come le ultime due righe erano più righe nel testo di input.)

Vincoli

  • Idealmente è necessaria una singola chiamata di sostituzione Regex
  • Uso della libreria .NET RegEx
  • Le virgolette sono sempre inizio / fine virgolette ricci, non semplici segni di spunta ("), il che dovrebbe rendere un po 'più facile.

Vincolo importante

Questo non è un codice .NET diretto, sto popolando una tabella di "cerca / sostituisci con" stringhe che vengono quindi chiamate tramite RegEx.Replace. Non ho la possibilità di aggiungere codice personalizzato come valutatori delle corrispondenze, scorrere i gruppi acquisiti, ecc.

Risposta attuale finora, qualcosa del genere:

r.Replace("(?<=“)\r\n(?=”)", " ")

Ovviamente, non sono ancora vicino.

La stessa logica potrebbe essere applicata, per esempio, alla codifica a colori dei commenti di blocco nel codice di programmazione - qualsiasi cosa all'interno del commento di blocco non viene trattata allo stesso modo delle cose esterne ai commenti. (Il codice è un po 'più complicato dal momento che i delimitatori del commento di blocco iniziale / finale possono anche esistere legittimamente all'interno di una stringa letterale, un problema che non devo affrontare qui.)

È stato utile?

Soluzione

Supponendo che tutte le virgolette siano correttamente bilanciate, questa regex dovrebbe fare quello che vuoi:

@"[\r\n]+(?=[^“”]*”)"

[\ r \ n] + corrisponderà a uno o più separatori di linea di qualsiasi tipo: Unix (\ n), DOS (\ r \ n) o Mac precedente (\ r) . Quindi il lookahead afferma che c'è una citazione ravvicinata e che non c'è una citazione aperta tra qui e là. Quindi il testo sostitutivo può essere un semplice carattere spaziale.

Altri suggerimenti

NB: per testare le regex uso http://gskinner.com/RegExr/ che è molto utile.

Non credo che tu possa scrivere una singola espressione che sostituirà un numero indefinito di newline. Tuttavia, puoi scrivere un'espressione per sostituirne una o più e eseguirla ripetutamente o scriverla per gestire il numero massimo di newline presenti in una sezione tra virgolette.

Per prima cosa, vuoi la modalità a riga singola in modo che la tua espressione corrisponda all'intera stringa di input invece che riga per riga. Mettilo all'inizio dell'espressione per attivarlo:

(?s)

Quindi, vuoi che un'espressione look-behind corrisponda alla citazione iniziale:

(?<=“)

E uno sguardo al futuro per abbinare la citazione finale:

(?=”)

Ora un'espressione per abbinare del testo, quindi una nuova riga, quindi del testo:

([^”\r]*)\r?([^”\r]*)

Nota che ci sono due gruppi di acquisizione per i bit di testo attorno alla nuova riga, quindi puoi includere quel testo nella tua espressione di sostituzione. Questo corrisponderà al testo che ha solo una nuova riga tra virgolette. Per estenderlo a due nuove righe, basta aggiungere un'altra riga nuova e il seguente testo facoltativo:

(?s)(?<=“)([^”\r]*)\r?([^”\r]*)\r?([^”\r]*)(?=”)

Potresti estenderlo per abbinare tutte le nuove righe che pensi possano verificarsi. Non perfetto, ma forse sufficiente. Oppure, se riesci a eseguire più volte l'espressione sul tuo testo, sostituiscine una sola alla volta.

Lasciando la tua espressione qualcosa del genere:

r.Replace("(?s)(?<=“)([^”\r]*)\r?([^”\r]*)", "$1 $2")

(Questo non è del tutto corretto in quanto aggiungerà uno spazio dopo il testo anche se il gruppo due non corrisponde ... ma è un inizio)

Quindi la cosa da fare è trovare una stringa che inizia con una virgoletta di apertura, seguita da una stringa che non contiene una virgoletta di chiusura o qualsiasi carattere \ r \ n, seguita da un serie di uno o più caratteri \ r \ n, cattura tutto tranne i caratteri \ r \ n terminali e sostituisce l'intera corrispondenza con la parte catturata.

- MarkusQ

Penso che il modo più semplice sarebbe quello di abbinare le sezioni citate con “(? s:. *?)” e usare un MatchEvaluator per rimuovere eventuali nuove righe. Il codice MatchEvaluator potrebbe essere semplice come

Replace(@"\s+", " ");

Potresti, ovviamente, perfezionare questo per abbinare solo le sezioni tra virgolette che contengono effettivamente nuove righe e sostituire solo le nuove righe all'interno di quelle sezioni invece di tutti gli spazi bianchi, ma probabilmente non vale la pena.

Non puoi fare ciò che vuoi entro i limiti che hai descritto.

La prova:

  • La tabella delle sostituzioni fissa eseguirà un numero fisso di chiamate da sostituire (chiamare questa n)
  • Ogni sostituzione sarà in grado di eliminare solo un numero fisso di interruzioni di linea (chiamare questo numero m).

Pertanto

  • Un blocco tra virgolette con m * n + 1 interruzioni di riga non verrà gestito correttamente.

Devi aumentare la potenza della tua configurazione (ad es. consentendo una sostituzione più complessa, sostituzioni ricorsive, un flag di ripetizione indefinito o ...?) o accettare il fatto che questa attività non può essere eseguita dal tuo motore .

- MarkusQ

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top