2012-03-13 2 views
5

Sto cercando di ottenere un'espressione regolare per rimuovere i commenti da un'istruzione SQL.Espressione regolare per rimuovere i commenti dall'istruzione SQL

Questa espressione regolare quasi funziona:

(/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/)|'(?:[^']|'')*'|(--.*) 

Excepth che l'ultima parte non gestisce "-" commenti molto bene. Il problema è la gestione delle stringhe SQL, delimitate da "".

Per esempio, se ho

SELECT ' -- Hello -- ' FROM DUAL 

Non dovrebbe corrispondere, ma è corrispondenza.

Questo è in ASP/VBscript.

Ho pensato di abbinare da destra a sinistra ma non credo che il motore regex di VBScript lo supporti. Anche provato a giocherellare con lookbehind negativo ma i risultati non erano buoni.

risposta

1

Come hai detto che il resto della tua regex va bene, mi sono concentrato sull'ultima parte. Tutto quello che dovete fare è verificare che il -- è all'inizio e poi assicurarsi che rimuove tutti i trattini se ci sono più di 2. L'espressione regolare finale è al di sotto

(^[--]+) 
È possibile che questo

è solo se si desidera rimuovere il commento scorre e non l'intera linea. È possibile eseguire il qui sotto se si vuole tutto quello che segue fino alla fine della linea, anche

(^--.*) 
+0

Hi Justin ... grazie per l'aiuto. Rimane il problema con i commenti in linea che non iniziano all'inizio. Come SELECT '- Hello -' FROM DUAL - commento che dovrebbe essere rimosso –

+0

Nessun problema, e benvenuti allo stack overflow. Per favore ricorda che il modo di mostrare apprezzamento qui è attraverso upvotes e risposte accettate (segno di spunta accanto alla risposta). Maggiori informazioni possono essere trovate nelle [FAQ], in particolare [FAQ # HowToAsk] How To Ask –

4

In PHP, sto usando questo codice per SQL decommentare:

$sqlComments = '@(([\'"]).*?[^\\\]\2)|((?:\#|--).*?$|/\*(?:[^/*]|/(?!\*)|\*(?!/)|(?R))*\*\/)\s*|(?<=;)\[email protected]'; 
/* Commented version 
$sqlComments = '@ 
    (([\'"]).*?[^\\\]\2) # $1 : Skip single & double quoted expressions 
    |(     # $3 : Match comments 
     (?:\#|--).*?$ # - Single line comments 
     |    # - Multi line (nested) comments 
     /\*    # . comment open marker 
      (?: [^/*] # . non comment-marker characters 
       |/(?!\*) # . ! not a comment open 
       |\*(?!/) # . ! not a comment close 
       |(?R) # . recursive case 
      )*   # . repeat eventually 
     \*\/    # . comment close marker 
    )\s*     # Trim after comments 
    |(?<=;)\s+   # Trim after semi-colon 
    @msx'; 
*/ 
$uncommentedSQL = trim(preg_replace($sqlComments, '$1', $sql)); 
preg_match_all($sqlComments, $sql, $comments); 
$extractedComments = array_filter($comments[ 3 ]); 
var_dump($uncommentedSQL, $extractedComments); 
+0

Questo è stellare ma non mi piaceva il ritaglio alla fine, perché può rimuovere le newline che potrebbero effettivamente essere desiderabili/necessarie (come quando un commento in linea dopo il codice non ha spazio prima ... le persone fanno questo: |). Aggiunti anche i backtick alla lista delle quotazioni. Quindi sto usando: $ sqlComments = '@ (([\' "']). *? [^ \\\] \ 2) | ((?: \ # | -). *? $ |/\ * (?: [^/*] |/(?! \ *) | \ * (?! /) | (? R)) * \ * \ /) + @ ms '; – dkloke

+0

Questo seggeults regexp (php 5.6) o restituisce NULL (php 7+) su query con lunghe commenti all'inizio, ad esempio ' /* mettere qui 8 KB di testo fittizio */ SELECT 1; ' –

+0

mi sono imbattuto in giro 120k query attraverso questa espressione regolare e ha alcuni grossi difetti nel rilevare i commenti nel mezzo di una query.Per esempio, vengono rimosse stringhe incapsulate correttamente contenenti "-" (doppia stringa di trattino) –

1

questo funziona codice per me:

function strip_sqlcomment ($string = '') { 
    $RXSQLComments = '@(--[^\r\n]*)|(\#[^\r\n]*)|(/\*[\w\W]*?(?=\*/)\*/)@ms'; 
    return (($string == '') ? '' : preg_replace($RXSQLComments, '', $string)); 
} 

con un po 'regex tweak potrebbe essere utilizzato per mettere a nudo i commenti in tutte le lingue

0

originale ho usato la soluzione di @Adrien Gibrat. Tuttavia, mi sono imbattuto in una situazione in cui non stava analizzando le stringhe citate, correttamente, se avessi qualcosa con un '-' precedente all'interno di esse. Ho finito per scrivere questo, invece:

'[^']*(?!\\)'(*SKIP)(*F)  # Make sure we're not matching inside of quotes 
|(?m-s:\s*(?:\-{2}|\#)[^\n]*$) # Single line comment 
|(?: 
    \/\*.*?\*\/     # Multi-line comment 
    (?(?=(?m-s:\h+$))   # Get trailing whitespace if any exists and only if it's the rest of the line 
    \h+ 
) 
) 

# Modifiers used: 'xs' ('g' can be used as well, but is enabled by default in PHP) 

Si prega di notare che questo dovrebbe essere usato quando PCRE è disponibile. Quindi, nel mio caso, sto usando una variazione di questo nella mia libreria PHP.

Example

+1

Questo è dolce! Ho aggiornato il regexp in modo che ignori i commenti non solo tra virgolette singole, ma anche virgolette doppie e apici inversi - https://regex101.com/r/GXb0a5/2 –

0

Si prega di vedere la mia risposta here. Funziona sia per i commenti della riga sia per i commenti del blocco , nidificati. Immagino sia necessario utilizzare espressioni regolari con i gruppi di bilanciamento , che AFAIK non è disponibile in VBScript.

-1

Per tutti gli utenti PHP: utilizzare questa libreria - https://github.com/jdorn/sql-formatter. Ho avuto a che fare con la rimozione dei commenti da SQL per un paio d'anni e l'unica soluzione valida sarebbe una macchina tokenizer/state, alla quale ho pazientemente resistito per scrivere.Un paio di giorni fa ho scoperto questa libreria e ho eseguito query a 120k e ho trovato un solo bug (https://github.com/jdorn/sql-formatter/issues/93), che è stato risolto immediatamente nella nostra forcella https://github.com/keboola/sql-formatter.

L'utilizzo è semplice

$query <<<EOF 
/* 
    my comments 
*/ 
SELECT 1; 
EOF; 

$bareQuery = \SqlFormatter::removeComments($query); 
// prints "SELECT 1;" 
print $bareQuery; 
+0

@BaummitAugen Grazie, risolto la risposta. –