¿Método simple para detectar de manera confiable el código en el texto?

142

GMail tiene esta función donde le avisará si intenta enviar un correo electrónico que cree podría tener un archivo adjunto.

DebidoaqueGMaildetectólacadenaseetheattachedenelcorreoelectrónico,peronounarchivoadjuntoreal,meadvierteconuncuadrodediálogoAceptar/CancelarcuandohagoclicenelbotónEnviar.

Tenemosunproblemarelacionadoconeldesbordamientodepila.Esdecir,cuandounusuarioingresaunapublicación como esta :

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");

Este usuario no dio formato a su código como code!

Es decir, no sangraron por 4 espacios por Markdown, ni usaron el botón de código (o el método abreviado de teclado ctrl + k ) que hace eso por ellos .

Por lo tanto, nuestro sistema está aceptando muchas ediciones en las que las personas tienen que ingresar y formatear manualmente el código de las personas que de alguna manera no pueden resolver esto. Esto lleva a Mucho dolor de vientre . Hemos mejorado la ayuda del editor varias veces, pero, aparte de conducir hasta la casa del usuario y presionar los botones correctos en su teclado, no podemos ver qué hacer a continuación.

Es por eso que estamos considerando una advertencia del estilo de Google GMail:

  

¿Querías publicar un código?

     

Escribiste cosas que creemos que parecen código, pero no lo formateaste como código al sangrar 4 espacios, usando el botón de código de la barra de herramientas o ctrl + k comando de formato de código.

Sin embargo, presentar esta advertencia requiere que detectemos la presencia de lo que creemos que es un código sin formato en una pregunta . ¿Cuál es una manera simple, semi-confiable de hacer esto?

  • Según Markdown , el código siempre está sangrado por 4 espacios o dentro de las comillas inversas, por lo que todo el formato correcto se puede descartar de la comprobar inmediatamente.
  • Esto es solo una advertencia y solo se aplicará a los usuarios de baja reputación que hagan sus primeras preguntas (o proporcionen sus primeras respuestas), por lo que algunos falsos positivos están bien, siempre y cuando se trate de 5% o menos.
  • Las preguntas sobre el desbordamiento de pila pueden estar en cualquier idioma, aunque podemos limitar de manera realista nuestro cheque a, por ejemplo, los idiomas "big ten". Por la página de etiquetas que sería C #, Java, PHP, JavaScript, Objective-C, C, C ++, Python, Ruby.
  • Utilice el volcado de datos de la comunidad creativa de desbordamiento de pila para auditar su solución potencial (o simplemente elija un algunas preguntas en las top 10 tags sobre desbordamiento de pila) y vea cómo lo hace.
  • El pseudocódigo está bien, pero usamos c # si quieres ser amigable.
  • Cuanto más simple, mejor (siempre y cuando funcione). ¡BESO! Si su solución requiere que intentemos compilar publicaciones en 10 compiladores diferentes, o un ejército de personas para entrenar manualmente un motor de inferencia bayesiano, eso no es exactamente lo que teníamos en mente.
pregunta Jeff Atwood 23.05.2017 - 14:40

14 respuestas

146

Una solución adecuada probablemente sería un modelo estadístico / aprendido, pero aquí hay algunas ideas divertidas:

  1. Puntos y coma al final de una línea . Esto solo atraparía un montón de idiomas.
  2. Los paréntesis siguen directamente el texto sin espacio para separarlo: myFunc()
  3. Un punto o flecha entre dos palabras: foo.bar = ptr->val
  4. Presencia de llaves, llaves: while (true) { bar[i]; }
  5. Presencia de sintaxis de "comentarios" (/ *, //, etc): /* multi-line comment */
  6. Caracteres / operadores no comunes: +, *, &, &&, |, ||, <, >, ==, !=, >=, <=, >>, <<, ::, __
  7. Ejecuta el resaltador de sintaxis en el texto. Si termina resaltando un alto porcentaje, probablemente sea un código.
  8. texto de camelCase en la publicación.
  9. paréntesis, llaves y / o paréntesis anidados.

Uno podría realizar un seguimiento del número de veces que aparece cada uno de estos, y estos podrían usarse como características en un algoritmo de aprendizaje automático como perceptron , como lo hace SpamAssassin.

    
respondido por el Yevgeniy Brikman 28.06.2011 - 18:20
54

Me gustaría saber cuáles son las métricas promedio del inglés escrito de un lado y el código del otro lado.

  • longitud de los párrafos
  • longitud de las líneas
  • tamaño de las palabras
  • caracteres utilizados
  • relación entre caracteres alfabéticos, numéricos y otros caracteres de símbolos
  • número de símbolos por palabra
  • etc.

Tal vez eso solo podría discriminar ya entre el código y el resto. Al menos creo que el código, sin importar el idioma, mostraría algunas métricas notablemente diferentes en muchos casos.

La buena noticia es que ya tienes una gran cantidad de datos sobre los que construir tus estadísticas.

Ok, he vuelto con algunos datos para respaldar mis suposiciones. :-)

Hice una prueba rápida y sucia en su propia publicación y en la primera publicación que encontré en StackOverflow , con una herramienta bastante avanzada: wc .

Esto es lo que tuve después de ejecutar wc en la parte de texto y en la parte de código de esos dos ejemplos:

Primero veamos la parte en inglés :

  • La parte en inglés de tu publicación (2635 caracteres, 468 palabras, 32 líneas)
    • 5 caracteres / palabra, 82 caracteres / línea, 14 palabras / línea
  • La parte en inglés de la otra publicación (1499 caracteres, 237 palabras, 12 líneas)
    • 6 caracteres / palabra, 124 caracteres / línea, 19 palabras / línea

Bastante similar, ¿no crees?

¡Ahora echemos un vistazo a la parte del código !

  • La parte del código de tu publicación (174 caracteres, 13 palabras, 3 líneas)
    • 13 caracteres / palabra, 58 caracteres / línea, 4 palabras / línea
  • La parte del código de la otra publicación (4181 caracteres, 287 palabras, 151 líneas)
    • 14 caracteres / palabra, 27 caracteres / línea, 2 palabras / línea

Vea qué tan diferentes no son esas métricas, pero lo más importante, ¿qué tan diferentes son de las métricas en inglés? Y esto es solo usando una herramienta limitada. Ahora estoy seguro de que puede obtener algo realmente preciso midiendo más métricas (estoy pensando en particular en las estadísticas de caracteres).

¿Puedo hacer una cookie?

    
respondido por el Julien Guertault 23.05.2017 - 14:40
23

Normalmente, las cadenas de Markov se usan para generar texto, pero también se pueden usar para predecir la similitud del texto (por CE Shannon 1950 ) a un modelo entrenado. Recomiendo múltiples cadenas de Markov.

Para cada idioma predominante, capacite a una cadena de Markov en una muestra grande y representativa de código en el idioma. Luego, para una publicación de desbordamiento de pila para la que desea detectar un código, haga lo siguiente para cada una de las cadenas:

  • Recorrer las líneas en la publicación.
    • Declare dos variables: ACTUAL = 1.0 y HIGHEST = 1.0
    • Recorra cada carácter de la línea.
      • Para cada carácter, encuentre la probabilidad en la cadena de Markov de que el carácter actual sea el siguiente a los N caracteres anteriores. Establezca ACTUAL = ACTUAL * PROB 1 . Si el carácter actual no está presente en la cadena, use un valor pequeño para PROB 1 , como 0.000001.
      • Ahora, encuentre el carácter más probable (es decir, la probabilidad más alta) de seguir los N caracteres anteriores. Establezca HIGHEST = HIGHEST * PROB 2 .
      • Obviamente, PROB 2 > = PROB 1

Para cada línea, debe tener un valor ACTUAL y el MÁS ALTO. Divide ACTUAL por el más alto. Eso le dará el puntaje de aptitud física para determinar si una línea en particular es un código fuente. Eso asociaría un número con cada una de las líneas en el ejemplo que dio:

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

Finalmente, deberás seleccionar un umbral para determinar cuándo hay un código en la publicación. Esto podría ser simplemente un número seleccionado por observación que produce un alto rendimiento. También podría tener en cuenta el número de líneas con una puntuación alta.

Entrenamiento

Para entrenar, procure una muestra grande y representativa de código en el idioma. Escriba un programa para recorrer el texto del código y asocie cada N-gramo en el archivo (el rango para N debe estar parametrizado) con la frecuencia estadística del carácter posterior. Esto producirá múltiples estados posibles de caracteres que siguen al bigrama, cada uno asociado con una probabilidad. Por ejemplo, el bigrama "()" podría tener algunas probabilidades de caracteres siguientes de:

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

El primero debe leerse, por ejemplo, como "La probabilidad de que un punto y coma siga una paréntesis vacía es 0.5".

Para entrenamiento, recomiendo N-gramas de tamaño de dos a cinco. Cuando hice una investigación sobre esto , encontramos que los N-gramos de tamaño dos a cinco funcionaron bien para ingles Dado que gran parte del código fuente es similar al inglés, sugeriría comenzar con ese rango y luego ajustar para encontrar los valores de parámetros óptimos a medida que encuentre lo que funciona.

Una advertencia: el modelo se verá afectado por identificadores, nombres de métodos, espacios en blanco, etc. Sin embargo, puede ajustar la capacitación para omitir ciertas características de la muestra de capacitación. Por ejemplo, podría colapsar todos los espacios en blanco innecesarios. La presencia de espacios en blanco en la entrada (la publicación de desbordamiento de pila) también se puede ignorar. También puede ignorar el caso alfabético, que sería más resistente en vista de las diferentes convenciones de nomenclatura de identificadores.

Durante mi investigación , encontramos que nuestros métodos funcionaron bien tanto en español como en inglés . No veo por qué esto tampoco funcionaría bien para el código fuente. El código fuente es aún más estructurado y predecible que el lenguaje humano.

    
respondido por el Matthew Rodatus 28.06.2011 - 13:28
13

¿Puedo sugerir un enfoque radicalmente diferente? En SO, la única lengua humana permitida es el inglés, por lo que todo lo que no sea inglés tiene 99.9% de posibilidades de ser un fragmento de código .

Entonces, mi solución sería: usar uno de los muchos verificadores de idioma inglés que hay por ahí (solo asegúrate de que también señalen, al lado de errores ortográficos, errores de sintaxis como puntos dobles o símbolos que no sean de idioma como # o ~ ). Luego, cualquier línea / párrafo que arroje una gran cantidad de errores y advertencias debería activar "¿es este código?" pregunta.

Este enfoque también se puede adaptar para aquellos sitios de StackExchange que usan otros idiomas además del inglés, por supuesto.

Solo mis 2 ¢ ...

    
respondido por el mac 28.06.2011 - 21:09
11

Probablemente obtendré unos cuantos votos negativos para esto, pero creo que te estás acercando a esto desde el ángulo equivocado.

Esta línea me tiene:

  

la gente tiene que entrar y manualmente   Código de formato para las personas que están   de alguna manera incapaz de resolver esto

OMI que el punto de vista es un poco arrogante. Encuentro esto mucho en el diseño de software, donde los programadores y diseñadores se molestan con los usuarios que no saben cómo usar el software correctamente, cuando el problema no es el usuario sino el software en sí, o al menos la interfaz de usuario. p>

La causa raíz de este problema no es el usuario, pero el hecho de que no sea obvio para ellos puede hacer esto.

¿Qué tal un cambio en la interfaz de usuario para que esto sea más obvio? Seguramente esto será:

  1. más obvio para los nuevos usuarios exactamente lo que necesitan hacer
  2. es más fácil para usted construir en lugar de escribir algoritmos complejos para detectar la lógica de código de una multitud de idiomas

Ejemplo:

    
respondido por el matt_asbury 28.06.2011 - 13:37
11

El pseudo código plantearía un verdadero desafío porque todo el lenguaje de programación depende de caracteres especiales como '[]', ';', '()', etc. Simplemente cuente la ocurrencia de estos caracteres especiales. Al igual que detectaría un archivo binario (más del 5% de una muestra contiene un byte de valor 0).

    
respondido por el Ivo Limmen 08.02.2012 - 06:53
4

Creo que es posible que tenga que apuntar esto solo a idiomas específicos, en general, este problema es probablemente intratable, ya que puede obtener idiomas que son bastante similares al inglés (por ejemplo, inform7 ). Pero afortunadamente, los más utilizados podrían cubrirse con bastante facilidad.

Mi primer corte sería buscar la secuencia "; \ n", que te proporcionará una buena combinación para C, C ++, Java, C # y cualquier otro lenguaje que use una sintaxis similar y que sea realmente simple. También es menos probable que se use en inglés que una; sin una nueva linea

    
respondido por el jk. 28.06.2011 - 10:19
4

Alguien mencionó que miraba las etiquetas y luego buscaba la sintaxis para eso, pero eso fue derribado porque estaba dirigido a nuevos usuarios.

Una posible solución mejor sería buscar nombres de idiomas en el cuerpo de la pregunta y luego aplicar la misma estrategia. Si menciono "Javascript", "Java" o "C #", es probable que de eso se trate la pregunta, y es probable que el código de la pregunta esté en ese idioma.

    
respondido por el Omar Kooheji 28.06.2011 - 11:43
1

Primero, ejecútalo a través del corrector ortográfico, encontrará muy pocas palabras correctas en inglés, sin embargo, debería haber muchas palabras que el corrector ortográfico sugerirá dividir.

Luego hay caracteres de puntuación / especiales que no son típicos del inglés simple, típicos del código:

  • something(); simplemente no puede ser simple inglés;
  • $something donde something no es todo numérico;
  • -> entre palabras sin espacios;
  • . entre palabras sin espacio;

Por supuesto, para que funcione bien, es posible que desee que el clasificador bayesiano se construya sobre estas características.

    
respondido por el vartec 28.06.2011 - 10:26
1

hay varios conjuntos de idiomas que comparten una sintaxis similar. la mayoría de los lenguajes se vieron influenciados por algunos lenguajes, por lo que los lenguajes [AMPL, AWK, csh, C ++, C--, C #, Objective-C, BitC, D, Go, Java, JavaScript, Limbo, LPC, Perl, PHP, Pike, Processing [todos fueron influenciados por C, por lo que si detectas C probablemente detectes todos estos idiomas. por lo tanto, solo tiene que escribir un patrón simple para detectar estos conjuntos de idiomas.

También dividiría el texto en bloques porque la mayoría del código se dividirá en dos líneas nuevas o similar de los otros bloques de texto en la publicación.

esto se puede hacer fácilmente con javascript (una muestra incompleta súper simple para la familia 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 + "]");
   }
}
    
respondido por el Michael van der Weg 28.06.2011 - 11:13
0

Simplemente cuente las palabras / puntuación para cada línea. El inglés tenderá a tener 4 o más, código menor que 2.

El párrafo anterior tiene 18 palabras y 4 caracteres de puntuación, por ejemplo. Este párrafo tiene 19 palabras y 4 puntuaciones, así que dentro de las expectativas.

Por supuesto, esto debería probarse frente a las preguntas de los principiantes de habla inglesa pobre, y puede ser que en esos casos, las estadísticas estén sesgadas.

Espero que [no sea el espacio en blanco]. [el espacio en blanco o la nueva línea] sea muy raro en el código, pero que sea común en inglés, por lo que esto podría considerarse como palabras, no como puntuación.

Creo que el mayor problema será el código en línea, donde alguien hace una pregunta como:

  

Si digo para (i = 0; i > 100; i ++) {} ¿qué significa eso?

Eso es código e inglés, y debe marcarse como si se tratara de marcas anteriores:

  

Si digo for (i=0; i>100; i++) {} , ¿qué significa eso?

    
respondido por el rjmunro 28.06.2011 - 12:36
0

Creo que primero debe hacer una distinción entre el código formateado (lo suficiente) que solo necesita ser designado como tal, y el código (también) mal formateado, que de todos modos necesita un formato manual.

El código formateado tiene líneas de división y sangría. Es decir: si una línea está precedida por una sola línea de ruptura, tiene un buen candidato. Si tiene espacios en blanco encima de eso, tiene un muy buen candidato.

El texto normal utiliza dos líneas de corte o dos espacios y una línea de corte para el formato, por lo que hay un criterio claro para la distinción.

En el código LISP no encontrarás puntos y comas, en el código Ruby no puedes encontrar paréntesis, en el pseudo código no puedes encontrar mucho. Pero en cualquier idioma (no esotérico) encontrará un código decente que se formateará con líneas de rotura y sangría. No hay nada tan universal como eso. Porque en el código final está escrito para ser leído por humanos.

Entonces, primero, busque posibles líneas de código . Además, las líneas de código suelen venir en grupos. Si tiene uno, es muy probable que el que está arriba o abajo también sea una línea de código.

Una vez que haya seleccionado las posibles líneas de código, puede compararlas con criterios cuantificables y elegir algún umbral :

  • frecuencia de caracteres que no son palabras
  • frecuencia de identificadores: palabras muy cortas o palabras muy largas con estilo CamelCase o under_score
  • repetición de palabras poco comunes

Además, ahora que hay programadores y cs, el alcance de stackoverflow está claramente reducido. Uno podría considerar denotar todas las etiquetas de idioma como idiomas. Y al publicar, se le pedirá que elija al menos una etiqueta de idioma, elija la etiqueta language-agnostic o que la omita explícitamente.

En el primer caso, usted sabe qué idiomas buscar, en el segundo caso, es posible que desee buscar un pseudocódigo y, en el último caso, probablemente no haya ningún código, porque es una pregunta relacionada con alguna tecnología o marco o tal.

    
respondido por el back2dos 28.06.2011 - 12:43
0

Puede crear un analizador para cada idioma que desee detectar (las definiciones de idioma para ANTLR generalmente son fáciles de encontrar) y luego ejecutar cada línea de la pregunta a través de cada analizador. Si alguna línea se analiza correctamente, probablemente tenga código.

El problema con esto es que algunas oraciones en inglés (lenguaje natural) se pueden analizar como código, por lo que es posible que desee incluir algunas de las otras ideas, o podría limitar los resultados positivos solo si hay más de una o dos líneas analizar correctamente con el mismo analizador de idioma.

El otro problema potencial es que esto probablemente no detectará el pseudocódigo, pero puede estar bien.

    
respondido por el Jeff Knecht 28.06.2011 - 13:52
0

Lo que puede ser el más seguro para el futuro y el menor ajuste manual a largo plazo, ya que otros lenguajes (que se ven algo diferentes a los lenguajes de programación más utilizados ahora) se vuelven más populares y los lenguajes utilizados actualmente se vuelven menos populares es hacer algo como lo que hace Google Translate (consulte el párrafo titulado "¿Cómo funciona?"), en su lugar de buscar ciertas cosas como ab y a (), etc.

En otras palabras, en lugar de pensar manualmente en los patrones que se encuentran en el código que debe buscar, la computadora puede resolverlo por sí misma . Esto se puede hacer teniendo

  1. muchos códigos en diferentes lenguajes de programación

    • Sugerencia: tome automáticamente muestras de código de repositorios de código fuente basados en la web como Google Code o Github, o incluso de cosas en Stackoverflow ya marcadas como código

    • Nota: puede ser una buena idea analizar los comentarios del código

  2. muchos textos en inglés tomados de artículos en la web

    • aunque no de artículos sobre programación (de lo contrario, pueden tener código y mezclar el sistema :-))

y teniendo algún tipo de algoritmo automáticamente encuentra patrones en el código que no están en inglés, y viceversa, y usa esos patrones para detectar qué es un código y qué no es un código ejecutando el algoritmo en los mensajes.

(Sin embargo, no estoy seguro de cómo funcionaría tal algoritmo. Otras respuestas a la pregunta actual pueden tener información útil para eso)

Luego, el sistema puede volver a escanear el código de vez en cuando para tener en cuenta los cambios en la forma en que el código mira ese punto en el tiempo.

    
respondido por el Abafei 28.06.2011 - 23:49