2013-12-08 8 views
6

Come posso scrivere un'espressione regolare che rileva l'utilizzo non corretto di una virgola in una stringa, vale a dire: 1. per non numeri, nessuno spazio prima e 1 spazio dopo; 2. per i numeri, le virgole sono consentite se precedute da 1-3 cifre e seguite da 3 cifre.Uso di espressioni regolari per verificare l'utilizzo della virgola

Alcuni casi di test:

  • ciao, mondo
  • ciao, mondo => errato
  • ciao, mondo => errati
  • 1.234 mondi
  • 1,23 mondi => errato
  • 1.2345 mondi => errato
  • ciao, 123 mondi => errato
  • ciao, 1234.567 mondi => errati
  • ciao, 12,34,567 mondi => errati
  • (nuovo test case) ciao 1, 2, e 3 mondi
  • (nuovo test case) ciao $ 1.234 mondi
  • (banco di prova nuovo) ciao $ 1,2345 mondi => errato
  • (nuovo test case) hello "1.234" mondi
  • 012.351.
  • (caso nuovo test) hello "1,23" mondi => errati

Così ho pensato che avrei dovuto una regex per catturare parole con sintassi cattiva via (?![\S\D],[\S\D]) (cattura dove c'è un non-spazio/cifra seguita da una virgola da un non-spazio/cifra) e unirsi a essa con un'altra regex per acquisire numeri con sintassi errata, tramite (?!(.?^(?:\d+|\d{1,3}(?:,\d{3}))(?:.\d+). Mettendoli insieme mi danno

preg_match_all("/(?![\S\D],[\S\D])|(?!(.*?^(?:\d+|\d{1,3}(?:,\d{3})*)(?:\.\d+)?$))/",$str,$syntax_result);

.. ma ovviamente non funziona. Come dovrebbe essere fatto?

================ EDIT ================

Grazie alla risposta Casimir et d'Ippolita sotto, ho fatto funzionare! Ho aggiornato la sua risposta per occuparmi di altri casi d'angolo. Idk se la sintassi che ho aggiunto è la più efficiente, ma funziona, per ora. Lo aggiornerò man mano che si presentano più casi d'angolo!

$pattern = <<<'LOD' 
~ 
(?: # this group contains allowed commas 
    [\w\)]+,((?=[ ][\w\s\(\"]+)|(?=[\s]+)) # comma between words or line break 
    | 
    (?<=^|[^\PP,]|[£$\s]) [0-9]{1,3}(?:,[0-9]{3})* (?=[€\s]|[^\PP,]|$) # thousands separator 
) (*SKIP) (*FAIL) # make the pattern fail and forbid backtracking 
| , # other commas 
~mx 
LOD; 
+0

Posso chiederti perché stai cercando di farlo? –

+0

Una possibile applicazione pratica: un paragrafo del testo viene estratto da un software OCR e voglio assicurarmi che la sintassi sia corretta prima di memorizzare il testo, usando questa applicazione come uno dei controlli grammaticali. (Nel mio caso il "software OCR" è un appaltatore economico di un paese non di lingua inglese che sta digitando il testo da un file pdf copiato) – Alex

risposta

3

non è impermeabile, ma questo può dare un'idea su come procedere:

$pattern = <<<'LOD' 
~ 
(?: # this group contains allowed commas 
    \w+,(?=[ ]\w+) # comma between words 
    | 
    (?<=^|[^\PP,]|[£$\s]) [0-9]{1,3}(?:,[0-9]{3})* (?=[€\s]|[^\PP,]|$) # thousands separator 
) (*SKIP) (*FAIL) # make the pattern fail and forbid backtracking 
| , # other commas 
~mx 
LOD; 

preg_match_all($pattern, $text, $matches, PREG_OFFSET_CAPTURE); 

print_r($matches[0]); 

L'idea è quella di escludere le virgole consentite dal risultato della partita per ottenere solo le virgole non corretta. Il primo gruppo non catturante contiene una sorta di lista nera per le situazioni corrette. (Puoi facilmente aggiungere altri casi).

[^\PP,] significa "tutti i caratteri di punteggiatura tranne ,", ma è possibile sostituire questa classe di caratteri da una lista più esplicita di caratteri consentiti, esempio: [("']

È possibile trovare maggiori informazioni su (*SKIP) e (*FAIL)here e here.

+0

Grazie! Questo ha funzionato brillantemente. E, ancora più importante, grazie per la lezione (Wow mi è rimasto molto da imparare sulla regex ..) – Alex

+0

Scusa - ho capito che ho bisogno di aggiungere casi per la "lista nera" per consentire stringhe come "Ho 1, 2, o 3 mele "ma non so come aggiungere correttamente i casi .. – Alex

+0

@AlexChang: questo caso è già supportato con' \ w +, (? = [] \ w +) 'poiché la classe' \ w' contiene anche cifre . –

Problemi correlati