web-dev-qa-db-fra.com

Une méthode simple pour détecter de manière fiable le code dans le texte?

GMail a cette fonctionnalité où il vous avertira si vous essayez d'envoyer un e-mail qu'il pense pourrait avoir une pièce jointe.

Did you mean to attach files?

Parce que GMail a détecté la chaîne see the attached dans l'e-mail, mais sans pièce jointe réelle, il m'avertit par une boîte de dialogue OK/Annuler lorsque je clique sur le bouton Envoyer.

Nous avons un problème connexe sur Stack Overflow. Autrement dit, lorsqu'un utilisateur entre dans un message comme celui-ci :

 mon problème est que je dois changer la base de données mais je ne vais pas créer 
 une nouvelle connexion. exemple: 
 
 DataSet dsMasterInfo = new DataSet (); 
 Database db = DatabaseFactory.CreateDatabase ("ConnectionString"); 
 DbCommand dbCommand = db.GetStoredProcCommand ("" uspGetMasterName "); 

Cet utilisateur n'a pas formaté son code comme code !

Autrement dit, ils n'ont pas mis en retrait de 4 espaces par Markdown, ou utiliser le bouton de code (ou le raccourci clavier ctrl+k) qui fait cela pour eux.

Ainsi, notre système accepte de nombreuses modifications où les gens doivent entrer et formater manuellement le code pour les personnes qui ne sont pas en mesure de comprendre cela. Cela conduit à beaucoup de bellyaching . Nous avons amélioré l'aide de l'éditeur à plusieurs reprises, mais à moins de conduire jusqu'à la maison de l'utilisateur et d'appuyer sur les bons boutons de son clavier pour lui, nous ne savons pas quoi faire ensuite.

C'est pourquoi nous envisageons un avertissement de style Google GMail:

Vouliez-vous publier le code?

Vous avez écrit des choses qui, à notre avis, ressemblent à du code, mais vous ne les avez pas formatées en tant que code en mettant en retrait 4 espaces, à l'aide du bouton de code de la barre d'outils ou du ctrl+k commande de formatage de code.

Cependant, la présentation de cet avertissement nous oblige à détecter la présence de ce que nous pensons être du code non formaté dans une question . Qu'est-ce qu'un moyen simple et semi-fiable de le faire?

  • Par Markdown , le code est toujours en retrait de 4 espaces ou entre guillemets, donc tout ce qui est correctement formaté peut être immédiatement supprimé de la vérification.
  • Ce n'est qu'un avertissement et cela ne s'appliquera qu'aux utilisateurs de mauvaise réputation posant leurs premières questions (ou fournissant leurs premières réponses), donc certains faux positifs sont OK, tant qu'ils sont environ 5 % ou moins.
  • Les questions sur Stack Overflow peuvent être dans la langue n'importe laquelle, bien que nous puissions raisonnablement limiter notre vérification aux, disons, les "dix grands" langages. Par la page des balises qui serait C #, Java, PHP, JavaScript, Objective-C, C, C++, Python, Ruby.
  • Utilisez le vidage des données communes Stack Overflow creative pour auditer votre solution potentielle (ou choisissez simplement quelques questions dans les 10 meilleures balises sur Stack Overflow) et voyez comment cela fonctionne.
  • Le pseudocode est bien, mais nous utilisons c # si vous voulez être très convivial.
  • Plus c'est simple, mieux c'est (tant que ça marche). BAISER! Si votre solution nous oblige à tenter de compiler des publications dans 10 compilateurs différents, ou une armée de personnes pour former manuellement un moteur d'inférence bayésien, ce n'est pas exactement ce que nous avions en tête.
144
Jeff Atwood

Une bonne solution serait probablement un modèle appris/statistique, mais voici quelques idées amusantes:

  1. Les points-virgules à la fin d'une ligne . Cela seul pourrait attraper tout un tas de langues.
  2. Entre parenthèses directement le texte suivant sans espace pour le séparer: myFunc()
  3. Un point ou une flèche entre deux mots: foo.bar = ptr->val
  4. Présence d'accolades, accolades: while (true) { bar[i]; }
  5. Présence de la syntaxe "commentaire" (/ *, //, etc.): /* multi-line comment */
  6. Caractères/opérateurs peu communs: +, *, &, &&, |, ||, <, >, ==, !=, >=, <=, >>, <<, ::, __
  7. Exécutez votre surligneur de syntaxe sur le texte. S'il finit par en mettre en évidence un pourcentage élevé, c'est probablement du code.
  8. camelCase texte dans le message.
  9. parenthèses, accolades et/ou crochets imbriqués.

On pourrait garder une trace du nombre de fois où chacun d'eux apparaît, et ceux-ci pourraient être utilisés comme fonctionnalités dans un algorithme d'apprentissage automatique comme perceptron , comme le fait SpamAssassin.

148
Yevgeniy Brikman

Je serais curieux de voir quelles sont les mesures moyennes de l'anglais écrit d'un côté et du code de l'autre côté.

  • longueur des paragraphes
  • longueur des lignes
  • taille des mots
  • caractères utilisés
  • rapport entre les caractères alphabétiques, numériques et autres symboles
  • nombre de symboles par mot
  • etc.

Peut-être que cela seul pourrait déjà faire la distinction entre le code et le reste. Au moins, je crois que le code, quelle que soit la langue, afficherait des mesures sensiblement différentes dans de nombreux cas.

La bonne nouvelle est que vous disposez déjà de nombreuses données sur lesquelles construire vos statistiques.


Ok, je suis de retour avec quelques données pour étayer mes hypothèses. :-)

J'ai fait un test rapide et sale sur votre propre post et sur le premier post que j'ai trouvé sur StackOverflow , avec un outil assez avancé: wc.

Voici ce que j'avais après avoir exécuté wc sur la partie texte et sur la partie code de ces deux exemples:

Voyons d'abord la partie anglaise :

  • La partie anglaise de votre message (2635 caractères, 468 mots, 32 lignes)
    • 5 caractères/mot, 82 caractères/ligne, 14 mots/ligne
  • La partie anglaise de l'autre message (1499 caractères, 237 mots, 12 lignes)
    • 6 caractères/mot, 124 caractères/ligne, 19 mots/ligne

Assez similaire, vous ne pensez pas?

Jetons maintenant un œil à la partie de code !

  • La partie code de votre message (174 caractères, 13 mots, 3 lignes)
    • 13 caractères/mot, 58 caractères/ligne, 4 mots/ligne
  • La partie code de l'autre message (4181 caractères, 287 mots, 151 lignes)
    • 14 caractères/mot, 27 caractères/ligne, 2 mots/ligne

Voyez à quel point ces métriques ne sont pas si différentes, mais plus important encore, à quel point elles sont différentes des métriques anglaises? Et cela utilise simplement un outil limité. Je suis maintenant sûr que vous pouvez obtenir quelque chose de vraiment précis en mesurant plus de métriques (je pense en particulier aux statistiques de caractères).

Puis-je utiliser des cookies?

54
Julien Guertault

En règle générale, les chaînes de Markov sont utilisées pour générer du texte, mais elles peuvent également être utilisées pour prédire la similitude du texte (par C.E. Shannon 195 ) avec un modèle entraîné. Je recommande plusieurs chaînes Markov.

Pour chaque langue courante, formez une chaîne de Markov sur un large échantillon représentatif de code dans la langue. Ensuite, pour une publication Stack Overflow pour laquelle vous souhaitez détecter du code, procédez comme suit pour chacune des chaînes:

  • Parcourez les lignes du message.
    • Déclarez deux variables: ACTUAL = 1.0 et HIGHEST = 1.0
    • Parcourez chaque caractère de la ligne.
      • Pour chaque caractère, trouvez la probabilité dans la chaîne de Markov que le caractère actuel soit celui qui suit les N caractères précédents. Réglez ACTUAL = ACTUAL * PROB1. Si le caractère actuel n'est pas présent dans la chaîne, utilisez une petite valeur pour PROB1, comme 0,000001.
      • Maintenant, trouvez le caractère le plus susceptible (c'est-à-dire la probabilité la plus élevée) de suivre les N caractères précédents. Réglez HIGHEST = HIGHEST * PROB2.
      • De toute évidence, PROB2 > = PROB1

Pour chaque ligne, vous devez avoir une valeur réelle et une valeur la plus élevée. Divisez ACTUAL par HIGHEST. Cela vous donnera le score de fitness pour savoir si une ligne particulière est du code source. Cela associerait un numéro à chacune des lignes de l'exemple que vous avez donné:

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

Enfin, vous devrez sélectionner un seuil pour déterminer quand il y a du code dans la publication. Cela pourrait simplement être un nombre sélectionné par observation qui donne des performances élevées. Il pourrait également prendre en compte le nombre de lignes avec un score élevé.

Formation

Pour vous entraîner, procurez-vous un large échantillon représentatif de code dans la langue. Écrivez un programme pour parcourir le texte du code et associer chaque N-gramme du fichier (la plage de N doit être paramétrée) à la fréquence statistique du caractère suivant. Cela produira plusieurs états de caractères possibles qui suivent le bigramme, chacun étant associé à une probabilité. Par exemple, le bigramme "()" pourrait avoir les probabilités de caractère suivantes:

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

Le premier doit être lu, par exemple comme "La probabilité qu'un point-virgule suive une parenthèse vide est de 0,5".

Pour la formation, je recommande N-grammes de taille deux à cinq. À l'époque où j'ai fait des recherches à ce sujet , nous avons constaté que les N-grammes de taille deux à cinq fonctionnaient bien pour l'anglais. Comme une grande partie du code source est comme l'anglais, je suggère de commencer par cette plage, puis de l'ajuster pour trouver les valeurs de paramètres optimales au fur et à mesure que vous trouvez ce qui fonctionne.

Une mise en garde: le modèle va être affecté par des identificateurs, des noms de méthode, des espaces, etc. Par exemple, vous pouvez réduire tous les espaces inutiles. La présence d'espaces dans l'entrée (le message Stack Overflow) peut également être ignorée. Vous pouvez également ignorer la casse alphabétique, qui serait plus résistante face aux différentes conventions de dénomination des identifiants.

Pendant mes recherches , nous avons constaté que nos méthodes fonctionnaient bien aussi bien en espagnol qu'en anglais. Je ne vois pas pourquoi cela ne fonctionnerait pas aussi bien pour le code source. Le code source est encore plus structuré et prévisible que le langage humain.

23
Matthew Rodatus

Puis-je suggérer une approche radicalement différente? Sur SO la seule langue humaine autorisée est l'anglais, donc tout ce qui n'est pas anglais a 99,9% de chances d'être un extrait de code.

Donc, ma solution serait: utilisez l'un des nombreux vérificateurs de langue en anglais (assurez-vous qu'ils signalent également - à côté des fautes d'orthographe - des erreurs de syntaxe comme les points doubles ou des symboles non linguistiques comme # ou ~). Ensuite, toute ligne/paragraphe qui génère une grande quantité d'erreurs et d'avertissements devrait déclencher le "est ce code?" question.

Cette approche peut également être adaptée pour les sites StackExchange utilisant d'autres langues que l'anglais, bien sûr.

Juste mon 2 ¢ ...

13
mac

Le pseudo-code poserait un véritable défi car tout langage de programmation dépend de caractères spéciaux comme '[]', ';', '()', etc. Comptez simplement l'occurrence de ces caractères spéciaux. Tout comme vous détecteriez un fichier binaire (plus de 5% d'un échantillon contient une valeur d'octet 0).

11
Ivo Limmen

Je vais probablement obtenir quelques votes négatifs pour cela, mais je pense que vous abordez cela sous le mauvais angle.

Cette ligne m'a fait:

les gens doivent entrer et formater manuellement le code pour les personnes qui sont en quelque sorte incapables de comprendre cela

OMI, ce point de vue est un peu arrogant. Je trouve cela beaucoup dans la conception de logiciels où les programmeurs et les concepteurs sont ennuyés par les utilisateurs qui ne savent pas comment utiliser correctement le logiciel, lorsque le problème n'est pas l'utilisateur mais le logiciel lui-même - ou l'interface utilisateur au moins.

La cause première de ce problème n'est pas l'utilisateur mais le fait qu'il ne leur soit pas évident qu'ils peuvent le faire.

Que diriez-vous d'un changement dans l'interface utilisateur pour rendre cela plus évident? Ce sera sûrement:

  1. plus évident pour les nouveaux utilisateurs exactement ce qu'ils doivent faire
  2. plus facile à construire que d'écrire des algorithmes complexes pour détecter la logique du code d'une multitude de langues

Exemple:

enter image description here

11
matt_asbury

Je pense que vous devrez peut-être cibler cela uniquement sur des langues spécifiques, en général, ce problème est probablement insoluble car vous pouvez obtenir des langues qui sont assez similaires à l'anglais (par exemple inform7 ). mais heureusement, les plus utilisés pouvaient être couverts assez facilement.

Ma première coupe serait de rechercher la séquence ";\n" qui vous donnerait une bonne correspondance pour C, C++, Java, C # et tout autre langage qui utilise une syntaxe similaire et est vraiment simple. Il est également moins susceptible d'être utilisé en anglais qu'un; sans nouvelle ligne

4
jk.

Quelqu'un a mentionné avoir regardé les balises, puis recherché la syntaxe pour cela, mais cela a été abattu car cela s'adresse aux nouveaux utilisateurs.

Une meilleure solution possible serait de rechercher des noms de langue dans le corps de la question, puis d'appliquer la même stratégie. Si je mentionne "Javascript", "Java" ou "C #", alors il y a de fortes chances que ce soit la question, et le code dans la question sera probablement dans cette langue.

4
Omar Kooheji

Tout d'abord, exécutez la vérification orthographique, il trouvera très peu de mots anglais appropriés, mais il devrait y avoir beaucoup de mots que le correcteur orthographique suggérera de diviser.

Ensuite, il y a des signes de ponctuation/spéciaux qui ne sont pas typiques de l'anglais ordinaire, typiques du code:

  • something(); ne peut tout simplement pas être en anglais simple;
  • $somethingsomething n'est pas entièrement numérique;
  • -> entre les mots sans espaces;
  • . entre les mots sans espace;

Bien sûr, pour qu'il fonctionne bien, vous voudrez peut-être que le classificateur bayésien soit construit en plus de ces caractéristiques.

1
vartec

il existe plusieurs ensembles de langages qui partagent une syntaxe similaire. la plupart des langages ont été influencés par quelques langages, donc les langages [AMPL, AWK, csh, C++, C--, C #, Objective-C, BitC, D, Go, Java, JavaScript, Limbo, LPC, Perl, PHP, Pike, Processing [étaient tous influencés par C, donc si vous détectez C, vous détecterez probablement tous ces langages. vous n'avez donc qu'à écrire un modèle simple pour détecter ces ensembles de langues.

je diviserais également le texte en blocs, car le plus de code sera divisé par deux nouvelles lignes ou similaires des autres blocs de texte dans le message.

cela peut être fait facilement avec javascript (un échantillon incomplet super simple pour la famille 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 + "]");
   }
}
1

Ce qui peut être le plus évolutif et nécessitera le moins d'ajustement manuel à long terme, car d'autres langages (qui semblent quelque peu différents des langages de programmation les plus utilisés actuellement) deviennent plus populaires et les langages actuellement utilisés deviennent moins populaires, c'est de faire quelque chose comme quoi Google Translate le fait (voir le paragraphe intitulé "Comment ça marche?"), au lieu de chercher certaines choses comme ab et a (), etc.

En d'autres termes, au lieu de penser manuellement aux modèles trouvés dans le code à rechercher, l'ordinateur peut le comprendre par lui-même . Cela peut être fait en ayant

  1. beaucoup de code dans de nombreux langages de programmation différents

    • Suggestion: prenez automatiquement des échantillons de code à partir de référentiels de code source basés sur le Web comme Google Code ou Github, ou même à partir d'éléments sur Stackoverflow déjà marqués comme code

    • Remarque: il peut être judicieux d'analyser les commentaires de code

  2. beaucoup de texte anglais extrait d'articles sur le web

    • mais pas d'articles sur la programmation (sinon ils peuvent contenir du code et mélanger le système :-))

et avoir une sorte d'algorithme automatiquement trouver des modèles dans le code qui ne sont pas en anglais, et vice versa, et utiliser ces modèles pour détecter ce qui est du code et ce qui ne l'est pas en exécutant l'algorithme sur les messages.

(Cependant, je ne sais pas comment un tel algorithme fonctionnerait. D'autres réponses à la question actuelle peuvent avoir des informations utiles pour cela.)

Ensuite, le système peut réexaminer le code de temps en temps pour tenir compte des changements dans la façon dont le code se présente à ce moment.

0
Abbafei

Comptez simplement les mots/caractères de ponctuation pour chaque ligne. L'anglais aura tendance à avoir 4 ou plus, code inférieur à 2.

Le paragraphe ci-dessus a 18 mots et 4 caractères de ponctuation, par exemple. Ce paragraphe a 19 mots et 4 ponctuations, donc dans les attentes.

Bien sûr, cela devrait être testé par rapport aux questions des débutants pauvres en anglais, et il se peut que dans ces cas, les statistiques soient biaisées.

Je m'attends à ce que [non-blanc]. [Blanc ou nouvelle ligne] soit très rare dans le code, mais commun en anglais, donc cela pourrait être compté comme des mots, pas de la ponctuation.

Je pense que le plus gros problème sera le code en ligne, où quelqu'un pose une question comme:

Si je dis pour (i = 0; i> 100; i ++) {} qu'est-ce que cela signifie?

C'est du code et de l'anglais, et devrait être marqué comme avec des tiques arrière:

Si je dis for (i=0; i>100; i++) {} qu'est-ce que cela signifie?

0
rjmunro

Je pense que vous devriez d'abord faire une distinction entre le code (suffisamment) formaté qui n'a besoin d'être désigné que comme tel, et le code (trop) mal formaté, qui a quand même besoin d'un formatage manuel.

Le code formaté a des lignes de rupture et une indentation. C'est-à-dire: si une ligne est précédée d'une seule ligne de rupture, vous avez un bon candidat. S'il y a des espaces blancs de premier plan en plus de cela, vous avez un très bon candidat.

Le texte normal utilise deux lignes de rupture ou deux espaces et une ligne de rupture pour la mise en forme, il existe donc un critère de distinction clair.

Dans le code LISP, vous ne trouverez pas de points-virgules, dans Ruby code vous ne trouverez peut-être pas de parenthèses, dans le pseudo-code vous ne trouverez peut-être pas grand-chose du tout. Mais dans n'importe quelle langue (non ésotérique) vous trouverez un code décent à mettre en forme avec des lignes de rupture et une indentation. Il n'y a rien d'aussi universel que cela. Parce qu'à la fin le code est écrit pour être lu par les humains.

Alors d'abord, recherche des lignes potentielles de code. De plus, les lignes de code viennent généralement en groupes. Si vous en avez un, il y a de fortes chances que celui ci-dessus ou ci-dessous soit également une ligne de code.

Une fois que vous avez sélectionné des lignes de code potentielles, vous pouvez les comparer à des critères quantifiables et choisir un certain seuil:

  • fréquence des caractères non Word
  • fréquence des identifiants: mots très courts ou très longs avec style CamelCase ou under_score
  • répétition de mots inhabituels

De plus, maintenant qu'il y a des programmeurs et des cs, la portée de stackoverflow est clairement réduite. On pourrait envisager de désigner toutes les balises de langue comme des langues. Et lors de la publication, vous serez invité à choisir au moins une balise de langue, choisissez le language-agnostic tag ou pour l'omettre explicitement.

Dans le premier cas, vous savez quelles langues rechercher, dans le second cas, vous voudrez peut-être rechercher un pseudo-code et dans le dernier cas, il n'y aura probablement pas de code, car c'est une question liée à une technologie ou cadre ou autre.

0
back2dos

Vous pouvez créer un analyseur pour chaque langue que vous souhaitez détecter (les définitions de langue pour ANTLR sont généralement faciles à trouver), puis exécuter chaque ligne de la question dans chaque analyseur. Si une ligne analyse correctement, vous avez probablement du code.

Le problème avec cela est que certaines phrases en anglais (langage naturel) peuvent être analysées en tant que code, vous pouvez donc également inclure certaines des autres idées, ou vous pouvez limiter les résultats positifs uniquement si plus d'une ou deux lignes consécutives analysent correctement avec le même analyseur de langue.

L'autre problème potentiel est que cela ne détectera probablement pas le pseudocode, mais cela peut être OK.

0
Jeff Knecht