Metodo semplice per il rilevamento affidabile del codice nel testo?

142

GMail ha questa funzione in cui ti avviserà se tenti di inviare un'email che pensa potrebbe avere un allegato.

PoichéGMailharilevatolastringaseetheattachednell'e-mail,manessunallegatoveroeproprio,miavvisaconunafinestradidialogoOK/AnnullaquandofaccioclicsulpulsanteInvia.

AbbiamounproblemacorrelatosuStackOverflow.Cioè,quandounutenteinserisceunpost come questo :

my problem is I need to change the database but I don't won't to create 
a new connection. example:

DataSet dsMasterInfo = new DataSet();
Database db = DatabaseFactory.CreateDatabase("ConnectionString");
DbCommand dbCommand = db.GetStoredProcCommand("uspGetMasterName");

Questo utente non ha formattato il suo codice come codice!

Cioè, non hanno indentato di 4 spazi per Markdown, o usano il tasto codice (o la scorciatoia da tastiera ctrl + k ) che fa questo per loro .

Pertanto, il nostro sistema accetta molte modifiche in cui le persone devono entrare e formattare manualmente il codice per le persone che in qualche modo non sono in grado di capirlo. Questo porta a un sacco di mal di pancia . Abbiamo migliorato l'aiuto dell'editor diverse volte, ma a parte andare a casa dell'utente e premere i pulsanti corretti sulla tastiera per loro, non sapremo cosa fare dopo.

Ecco perché stiamo prendendo in considerazione un avvertimento sullo stile di Google GMail:

Did you mean to post code?

You wrote stuff that we think looks like code, but you didn't format it as code by indenting 4 spaces, using the toolbar code button or the ctrl+k code formatting command.

Tuttavia, la presentazione di questo avviso ci obbliga a rilevare la presenza di ciò che pensiamo sia un codice non formattato in una domanda . Qual è un modo semplice e semi-affidabile per farlo?

  • Per Markdown , il codice è sempre rientrato di 4 spazi o all'interno di apici inversi, quindi qualsiasi cosa formattata correttamente può essere scartata dal controllare immediatamente.
  • Questo è solo un avviso e si applicherà solo agli utenti di bassa reputazione che fanno le loro prime domande (o forniscono le loro prime risposte), quindi alcuni falsi positivi sono OK, purché siano circa 5% o meno.
  • Le domande su Stack Overflow possono trovarsi in qualsiasi lingua, sebbene possiamo limitare realisticamente il nostro assegno, ad esempio, alle "dieci grandi" lingue. Per la pagina dei tag che sarebbe C #, Java, PHP, JavaScript, Objective-C, C, C ++, Python, Ruby.
  • Utilizza il scarico di dati sulle risorse creative di overflow dello stack per verificare la tua potenziale soluzione (o semplicemente scegli un alcune domande nei top 10 tag su Stack Overflow) e guarda come funziona.
  • Lo pseudocodice va bene, ma usiamo c # se vuoi essere più amichevole.
  • Più semplice è, meglio è (finché funziona). BACIO! Se la tua soluzione ci richiede di tentare di compilare post in 10 compilatori diversi, o un esercito di persone per addestrare manualmente un motore inferenziale bayesiano, non è esattamente quello che avevamo in mente.
posta Jeff Atwood 23.05.2017 - 14:40
fonte

14 risposte

146

Una soluzione adeguata sarebbe probabilmente un modello imparato / statistico, ma qui ci sono alcune idee divertenti:

  1. Punti e virgola alla fine di una riga . Solo questo avrebbe catturato un sacco di lingue.
  2. Le parentesi seguono direttamente il testo senza spazio per separarlo: myFunc()
  3. Un punto o una freccia tra due parole: foo.bar = ptr->val
  4. Presenza di parentesi graffe, parentesi: while (true) { bar[i]; }
  5. Presenza della sintassi "commento" (/ *, //, ecc.): /* multi-line comment */
  6. Caratteri / operatori non comuni: +, *, &, &&, |, ||, <, >, ==, !=, >=, <=, >>, <<, ::, __
  7. Esegui il tuo Evidenziatore di sintassi sul testo. Se finisce per evidenziare una percentuale elevata di esso, probabilmente è il codice.
  8. CamelCase text nel post.
  9. parentesi, parentesi e / o parentesi annidate

Si potrebbe tenere traccia del numero di volte in cui ciascuna di queste appare, e queste potrebbero essere usate come caratteristiche in un algoritmo di apprendimento automatico come perceptron , come fa SpamAssassin.

    
risposta data 28.06.2011 - 18:20
fonte
54

Sarei curioso di vedere quali sono le metriche medie dell'inglese scritto su un lato e il codice sull'altro lato.

  • lunghezza dei paragrafi
  • lunghezza delle linee
  • dimensione delle parole
  • caratteri usati
  • rapporto tra caratteri alfabetici, numerici e di altri simboli
  • numero di simboli per parola
  • ecc.

Forse questo da solo potrebbe già discriminare tra il codice e il resto. Almeno credo che il codice, a prescindere dal linguaggio, mostrerebbe in alcuni casi metriche notevolmente diverse.

La buona notizia è che hai già un sacco di dati per costruire le tue statistiche.

Ok sono tornato con alcuni dati per supportare le mie ipotesi. : -)

Ho eseguito un test rapido e sporco sul tuo post e su il primo post che ho trovato su StackOverflow , con uno strumento abbastanza avanzato: wc .

Ecco cosa ho avuto dopo aver eseguito wc sulla parte di testo e sulla parte di codice di questi due esempi:

Per prima cosa, guarda la parte inglese :

  • La parte inglese del tuo post (2635 caratteri, 468 parole, 32 righe)
    • 5 caratteri / parola, 82 caratteri / riga, 14 parole / riga
  • La parte inglese dell'altro post (1499 caratteri, 237 parole, 12 righe)
    • 6 caratteri / parola, 124 caratteri / riga, 19 parole / riga

Piuttosto simile, non credi?

Ora diamo un'occhiata alla parte del codice !

  • La parte del codice del tuo post (174 caratteri, 13 parole, 3 righe)
    • 13 caratteri / parola, 58 caratteri / riga, 4 parole / riga
  • La parte del codice dell'altro post (4181 caratteri, 287 parole, 151 righe)
    • 14 caratteri / parola, 27 caratteri / riga, 2 parole / riga

Scopri come non sono così diverse queste metriche, ma, soprattutto, quanto sono diverse dalle metriche inglesi? E questo è solo usando uno strumento limitato. Ora sono sicuro che puoi ottenere qualcosa di veramente accurato misurando più metriche (sto pensando in particolare alle statistiche dei caratteri).

Posso cookie haz?

    
risposta data 23.05.2017 - 14:40
fonte
23

Tipicamente, le catene Markov sono usate per generare testo, ma possono anche essere usate per prevedere la somiglianza del testo (per CE Shannon 1950 ) a un modello addestrato. Raccomando più catene Markov.

Per ogni lingua prevalente, forma una catena Markov su un campione numeroso e rappresentativo di codice nella lingua. Quindi, per un post di Overflow di stack per il quale si desidera rilevare il codice, effettuare le seguenti operazioni per ciascuna catena:

  • Passa attraverso le linee nel post.
    • Dichiarare due variabili: ACTUAL = 1.0 e HIGHEST = 1.0
    • Passa attraverso ogni personaggio della linea.
      • Per ogni personaggio, trova la probabilità nella catena di Markov che il carattere corrente sia quello che segue i precedenti N caratteri. Imposta ACTUAL = ACTUAL * PROB 1 . Se il carattere corrente non è presente nella catena, utilizza un valore minuscolo per PROB 1 , come 0.000001.
      • Ora, trova il personaggio più probabile (cioè la probabilità più alta) di seguire i precedenti N caratteri. Imposta HIGHEST = HIGHEST * PROB 2 .
      • Ovviamente, PROB 2 > = PROB 1

Per ogni riga, dovresti avere un valore EFFETTIVO e un valore ALTRO. Dividi ATTUALE per ALTO. Questo ti darà il punteggio di fitness se una particolare linea è il codice sorgente. Questo assocerebbe un numero a ciascuna delle linee nell'esempio che hai dato:

my problem is I need to change the database but I don't won't to create // 0.0032
a new connection. example: // 0.0023

DataSet dsMasterInfo = new DataSet(); // 0.04
Database db = DatabaseFactory.CreateDatabase("ConnectionString");   // 0.05
DbCommand dbCommand = db.GetStoredProcCommand("uspGetMasterName");  // 0.04

Infine, dovrai selezionare una soglia per determinare quando c'è del codice nel post. Questo potrebbe essere semplicemente un numero selezionato dall'osservazione che produce prestazioni elevate. Potrebbe anche prendere in considerazione il numero di linee con un punteggio elevato.

Formazione

Per addestrare, procurati un campione numeroso e rappresentativo di codice nella lingua. Scrivi un programma per eseguire il loop del testo del codice e associare ciascun N-gram nel file (l'intervallo per N deve essere parametrizzato) con la frequenza statistica del carattere successivo. Ciò produrrà più possibili stati di caratteri che seguono il bigram, ciascuno associato a una probabilità. Ad esempio, il bigram "()" potrebbe avere alcune seguenti probabilità di carattere:

"()" 0.5-> ";"
"()" 0.2-> "."
"()" 0.3-> "{"

Il primo dovrebbe essere letto, ad esempio come "La probabilità che un punto e virgola segua una parentesi vuota è 0.5."

Per gli allenamenti, raccomando N-grammi di taglia da due a cinque. Indietro quando ho fatto qualche ricerca su questo , abbiamo scoperto che le dimensioni N-grammi da due a cinque funzionavano bene per l'inglese. Dal momento che gran parte del codice sorgente è simile all'inglese, suggerirei di iniziare con quell'intervallo e quindi di aggiustarlo per trovare i valori dei parametri ottimali quando trovi ciò che funziona.

Un avvertimento: il modello sarà influenzato da identificatori, nomi di metodi, spazi bianchi, ecc. Tuttavia, è possibile ottimizzare l'allenamento per omettere alcune caratteristiche del campione di allenamento. Ad esempio, potresti comprimere tutti gli spazi bianchi non necessari. Anche la presenza di spazi bianchi nell'input (il post Overflow dello stack) può essere ignorata. Potresti anche ignorare il caso alfabetico, che sarebbe più resistente di fronte alle diverse convenzioni di denominazione degli identificatori.

Durante la mia ricerca , abbiamo scoperto che i nostri metodi funzionavano bene sia per lo spagnolo che per l'inglese . Non vedo perché questo non funzionerebbe bene anche per il codice sorgente. Il codice sorgente è ancora più strutturato e prevedibile del linguaggio umano.

    
risposta data 28.06.2011 - 13:28
fonte
13

Posso suggerire un approccio radicalmente diverso? Su SO l'unica lingua consentita è l'inglese, quindi tutto ciò che non è inglese ha il 99,9% di possibilità di essere uno snippet di codice .

Quindi la mia soluzione sarebbe: usa uno dei tanti controllori di lingua inglese là fuori (assicurati che segnalino anche - a parte errori di ortografia - errori di sintassi come i doppi punti, o simboli non linguistici come # o ~ ). Quindi qualsiasi linea / paragrafo che genera una grande quantità di errori e avvertenze dovrebbe innescare il "è questo codice?" domanda.

Questo approccio può anche essere adattato per quei siti StackExchange utilizzando lingue diverse dall'inglese, naturalmente.

Solo il mio 2 ¢ ...

    
risposta data 28.06.2011 - 21:09
fonte
11

Probabilmente avrò voti bassi per questo, ma penso che ti stai avvicinando dall'angolo sbagliato.

Questa frase mi ha dato:

people have to go in and manually format code for people that are somehow unable to figure this out

IMO che punto di vista è una specie di arrogante. Lo trovo molto nella progettazione di software in cui programmatori e designer si infastidiscono con utenti che non riescono a capire come utilizzare il software correttamente, quando il problema non è l'utente ma il software stesso - o almeno l'interfaccia utente.

La causa principale di questo problema non è l'utente ma il fatto che non è ovvio per loro che possono farlo.

Che ne dici di un cambiamento nell'interfaccia utente per renderlo più ovvio? Sicuramente questo sarà:

  1. più ovvio per i nuovi utenti esattamente quello che devono fare
  2. più facile da costruire piuttosto che scrivere algoritmi complessi per rilevare la logica del codice di una moltitudine di lingue

Esempio:

    
risposta data 28.06.2011 - 13:37
fonte
11

Lo pseudo codice rappresenterebbe una vera sfida perché tutto il linguaggio di programmazione dipende da caratteri speciali come '[]', ';', '()', ecc. Basta contare l'occorrenza di questi caratteri speciali. Proprio come se dovessi rilevare un file binario (più del 5% di un campione contiene il valore di byte 0).

    
risposta data 08.02.2012 - 06:53
fonte
4

Penso che potrebbe essere necessario indirizzarlo contro solo lingue specifiche, in generale questo problema è probabilmente intrattabile in quanto è possibile ottenere lingue che sono abbastanza simili all'inglese (ad esempio inform7 ). ma per fortuna i più usati potrebbero essere coperti abbastanza facilmente.

Il mio primo taglio sarebbe quello di cercare la sequenza "; \ n" che ti farà ottenere una buona corrispondenza per C, C ++, Java, C # e qualsiasi altro linguaggio che usi la sintassi simile ed è davvero semplice. È anche meno probabile che venga usato in inglese di un; senza una nuova riga

    
risposta data 28.06.2011 - 10:19
fonte
4

Qualcuno ha menzionato l'aspetto dei tag e poi cercava la sintassi, ma è stato abbattuto perché è indirizzato ai nuovi utenti.

Una possibile soluzione migliore sarebbe cercare nomi di lingue nel corpo della domanda, quindi applicare la stessa strategia. Se menziono "Javascript", "Java" o "C #", è probabile che sia di questo che si tratta, e il codice nella domanda rischia di essere in quella lingua.

    
risposta data 28.06.2011 - 11:43
fonte
1

Per prima cosa, esegui il controllo ortografico, troverai pochissime parole inglesi corrette, tuttavia ci dovrebbero essere molte parole che il correttore ortografico suggerirà di suddividere.

Poi ci sono caratteri di punteggiatura / speciali non tipici per l'inglese semplice, tipico per il codice:

  • something(); non può essere semplicemente inglese;
  • $something dove something non è tutto numerico;
  • -> tra parole senza spazi;
  • . tra parole senza spazio;

Ovviamente per farlo funzionare bene, potresti voler avere un classificatore bayesiano basato su queste caratteristiche.

    
risposta data 28.06.2011 - 10:26
fonte
1

ci sono diversi gruppi di lingue che condividono sintassi simile. la maggior parte delle lingue è influenzata da alcune lingue, quindi le lingue [AMPL, AWK, csh, C ++, C--, C #, Objective-C, BitC, D, Go, Java, JavaScript, Limbo, LPC, Perl, PHP, Pike, Processing [sono stati tutti influenzati da C, quindi se rilevi C probabilmente rileverai tutte queste lingue. quindi devi solo scrivere un modello semplice per rilevare questo set di lingue.

Anch'io dividerei il testo in blocchi perché la maggior parte del codice verrà divisa da due newline o simili dagli altri blocchi di testo nel post.

questo può essere fatto facilmente con javascript (un campione incompleto supersimo per la famiglia c):

var txt = "my problem is I need to change the database but I don't won't to create a new connection. example:\n\nDataSet dsMasterInfo = new DataSet();Database db = DatabaseFactory.CreateDatabase(&quot;ConnectionString&quot;);DbCommand dbCommand = db.GetStoredProcCommand(&quot;uspGetMasterName&quot;);";
var blocks = txt.split(/\n\n/gi); console.dir(blocks);
var i = blocks.length;
var cReg = /if\s*\(.+?\)|.*(?:int|char|string|short|long).*?=.+|while\s*\(.+?\)/gi;

while ( i-- ){
   var current = blocks[i];
   if ( cReg.test( current ) ){
      console.log("found code in block[" +  i + "]");
   }
}
    
risposta data 28.06.2011 - 11:13
fonte
0

Conta semplicemente parole / caratteri di punteggiatura per ogni riga. L'inglese tende ad avere 4 o più, codice inferiore a 2.

Il paragrafo sopra ha 18 parole e 4 caratteri di punteggiatura, per esempio. Questo paragrafo ha 19 parole e 4 segni di punteggiatura, quindi entro le aspettative.

Ovviamente, questo dovrebbe essere testato contro le domande dei newbie poor-english speakers, e potrebbe essere che in questi casi le statistiche siano distorte.

Mi aspetto che [non-spazio bianco]. [spazio bianco o newline] sia molto raro nel codice, ma comune in inglese, quindi questo potrebbe essere contato come parole, non punteggiatura.

Penso che il problema più grande sarà il codice inline, in cui qualcuno fa una domanda del tipo:

If I say for (i=0; i>100; i++) {} what does that mean?

Questo è il codice e l'inglese, e dovrebbe essere contrassegnato come back-ticks:

If I say for (i=0; i>100; i++) {} what does that mean?

    
risposta data 28.06.2011 - 12:36
fonte
0

Penso che dovresti prima fare una distinzione tra codice (sufficientemente) formattato che deve solo essere effettivamente indicato come tale e (troppo) codice formattato male, che comunque richiede la formattazione manuale.

Il codice formattato ha interruzioni e rientri. Cioè: se una linea è preceduta da una singola linea di frattura, hai un buon candidato. Se ha degli spazi bianchi in testa, hai un ottimo candidato.

Il testo normale utilizza due linee di separazione o due spazi e una linea di separazione per la formattazione, quindi c'è un chiaro criterio per la distinzione.

Nel codice LISP non troverai il punto e virgola, nel codice Ruby potresti non trovare parentesi, in pseudo codice potresti non trovare molto. Ma in qualsiasi linguaggio (non esoterico) troverai del codice decente da formattare con linee di discontinuità e rientri. Non c'è nulla di così universale. Perché nel codice finale è scritto per essere letto dagli umani.

Quindi, per prima cosa cerca le linee di codice potenziali. Inoltre, le righe di codice di solito vengono in gruppi. Se ne hai uno, ci sono buone possibilità che quello sopra o sotto sia una linea di codice.

Dopo aver individuato potenziali righe di codice, puoi controllarle in base a criteri quantificabili e selezionare alcune soglie :

  • frequenza di caratteri non parole
  • frequenza degli identificatori: parole molto brevi o parole molto lunghe con stile CamelCase o under_score
  • ripetizione di parole non comuni

Inoltre, ora che ci sono programmatori e c, l'ambito di StackOverflow è chiaramente ridotto. Si potrebbe considerare di denotare tutti i tag di lingua come lingue. E quando pubblichi, ti verrà chiesto di scegliere almeno un tag di lingua, selezionare il tag language-agnostic o di ometterlo esplicitamente.

Nel primo caso sai quali lingue cercare, nel secondo caso potresti voler cercare lo pseudo-codice e, nell'ultimo caso, probabilmente non ci sarà alcun codice, perché è una domanda relativa a alcune tecnologie o framework o simili.

    
risposta data 28.06.2011 - 12:43
fonte
0

Potresti creare un parser per ciascuna lingua che vuoi rilevare (le definizioni di linguaggio per ANTLR sono solitamente facili da trovare), quindi esegui ogni riga della domanda attraverso ogni parser. Se una riga analizza correttamente, probabilmente hai il codice.

Il problema con questo è che alcune frasi inglesi (linguaggio naturale) possono essere analizzate come codice, quindi potresti voler includere anche alcune delle altre idee, oppure potresti limitare i risultati positivi solo se più di una o due righe consecutive analizzare correttamente con lo stesso parser di lingua.

L'altro potenziale problema è che probabilmente questo non prenderà lo pseudocodice, ma potrebbe essere OK.

    
risposta data 28.06.2011 - 13:52
fonte
0

Quello che potrebbe essere il più a prova di futuro e richiedere la minima regolazione manuale a lungo termine, poiché altri linguaggi (che sembrano in qualche modo diversi dai linguaggi di programmazione più usati ora) diventano più popolari e le lingue attualmente utilizzate diventano meno popolari, è fare qualcosa di simile a ciò che Google Translate (vedi il paragrafo intitolato "Come funziona?"), invece di cercare alcune cose come ab e a (), ecc.

In altre parole, invece di pensare manualmente ai pattern trovati nel codice da cercare, il computer può capirlo da solo . Questo può essere fatto avendo

  1. molto codice in molti linguaggi di programmazione

    • Suggerimento: prendi automaticamente campioni di codice da repository di codice sorgente basati sul web come Google Code o Github, o anche da cose su Stackoverflow già contrassegnati come codice

    • Nota: potrebbe essere una buona idea analizzare i commenti del codice

  2. molto testo in inglese tratto dagli articoli sul Web

    • anche se non da articoli sulla programmazione (altrimenti potrebbero avere del codice e mixare il sistema :-))

e avere un qualche tipo di algoritmo automaticamente trova i pattern nel codice che non sono in inglese, e viceversa, e usa quei pattern per rilevare cosa è codice e cosa non è codice eseguendo il algoritmo sui post.

(Tuttavia, non sono sicuro di come funzionerebbe un simile algoritmo. Altre risposte alla domanda corrente potrebbero avere informazioni utili per questo.)

Quindi il sistema può rieseguire la scansione del codice ogni tanto per tenere conto delle modifiche nel modo in cui il codice viene visualizzato in quel momento.

    
risposta data 28.06.2011 - 23:49
fonte