Apa cara terbaik untuk mendeteksi bahasa pemrograman apa yang digunakan dalam cuplikan kode?
Apa cara terbaik untuk mendeteksi bahasa pemrograman apa yang digunakan dalam cuplikan kode?
Jawaban:
Saya pikir metode yang digunakan dalam filter spam akan bekerja dengan sangat baik. Anda membagi potongan menjadi kata-kata. Kemudian Anda membandingkan kemunculan kata-kata ini dengan cuplikan yang diketahui, dan menghitung kemungkinan bahwa cuplikan ini ditulis dalam bahasa X untuk setiap bahasa yang Anda minati.
http://en.wikipedia.org/wiki/Bayesian_spam_filtering
Jika Anda memiliki mekanisme dasar, maka sangat mudah untuk menambahkan bahasa baru: cukup latih detektor dengan beberapa cuplikan dalam bahasa baru (Anda dapat memberinya proyek sumber terbuka). Dengan cara ini ia mempelajari bahwa "Sistem" kemungkinan besar muncul di cuplikan C # dan "menempatkan" di cuplikan Ruby.
Saya sebenarnya menggunakan metode ini untuk menambahkan deteksi bahasa ke cuplikan kode untuk perangkat lunak forum. Ini berhasil 100% dari waktu, kecuali dalam kasus yang ambigu:
print "Hello"
Biarkan saya menemukan kodenya.
Saya tidak dapat menemukan kodenya, jadi saya membuat yang baru. Ini agak sederhana tetapi berfungsi untuk pengujian saya. Saat ini jika Anda memberinya lebih banyak kode Python daripada kode Ruby, kemungkinan akan mengatakan bahwa kode ini:
def foo
puts "hi"
end
adalah kode Python (meskipun sebenarnya itu Ruby). Ini karena Python juga memiliki def
kata kunci. Jadi jika telah melihat 1000x def
di Python dan 100x def
di Ruby maka itu mungkin masih mengatakan Python puts
dan end
spesifik untuk Ruby. Anda dapat memperbaikinya dengan melacak kata-kata yang terlihat per bahasa dan membaginya di suatu tempat (atau dengan memberinya jumlah kode yang sama dalam setiap bahasa).
Saya harap ini membantu Anda:
class Classifier
def initialize
@data = {}
@totals = Hash.new(1)
end
def words(code)
code.split(/[^a-z]/).reject{|w| w.empty?}
end
def train(code,lang)
@totals[lang] += 1
@data[lang] ||= Hash.new(1)
words(code).each {|w| @data[lang][w] += 1 }
end
def classify(code)
ws = words(code)
@data.keys.max_by do |lang|
# We really want to multiply here but I use logs
# to avoid floating point underflow
# (adding logs is equivalent to multiplication)
Math.log(@totals[lang]) +
ws.map{|w| Math.log(@data[lang][w])}.reduce(:+)
end
end
end
# Example usage
c = Classifier.new
# Train from files
c.train(open("code.rb").read, :ruby)
c.train(open("code.py").read, :python)
c.train(open("code.cs").read, :csharp)
# Test it on another file
c.classify(open("code2.py").read) # => :python (hopefully)
$
, jadi mungkin Anda tidak boleh memisahkan batas kata, karena $
harus tetap dengan variabel. Operator suka =>
dan :=
harus terikat bersama sebagai satu token, tetapi OTH Anda mungkin harus berpisah {
karena mereka selalu berdiri sendiri.
Deteksi bahasa diselesaikan oleh orang lain:
Pendekatan Ohloh: https://github.com/blackducksw/ohcount/
Pendekatan Github: https://github.com/github/linguist
Anda mungkin menemukan beberapa materi berguna di sini: http://alexgorbatchev.com/wiki/SyntaxHighlighter . Alex telah menghabiskan banyak waktu untuk mencari tahu cara mengurai sejumlah besar bahasa yang berbeda, dan apa elemen sintaks utamanya.
Guesslang adalah solusi yang mungkin:
http://guesslang.readthedocs.io/en/latest/index.html
Ada juga SourceClassifier:
https://github.com/chrislo/sourceclassifier/tree/master
Saya menjadi tertarik dengan masalah ini setelah menemukan beberapa kode dalam artikel blog yang tidak dapat saya identifikasi. Menambahkan jawaban ini karena pertanyaan ini adalah pencarian pertama untuk "mengidentifikasi bahasa pemrograman".
Ini sangat sulit dan terkadang tidak mungkin. Dari bahasa manakah cuplikan singkat ini berasal?
int i = 5;
int k = 0;
for (int j = 100 ; j > i ; i++) {
j = j + 1000 / i;
k = k + i * j;
}
(Petunjuk: Bisa salah satu dari beberapa.)
Anda dapat mencoba menganalisis berbagai bahasa dan mencoba memutuskan menggunakan analisis frekuensi kata kunci. Jika kumpulan kata kunci tertentu muncul dengan frekuensi tertentu dalam teks, kemungkinan besar bahasanya adalah Java, dll. Tapi saya rasa Anda tidak akan mendapatkan apa pun yang sepenuhnya merupakan bukti bodoh, karena Anda dapat memberi nama misalnya variabel dalam C dengan nama yang sama sebagai kata kunci di Jawa, dan analisis frekuensi akan tertipu.
Jika Anda meningkatkan kerumitannya, Anda dapat mencari struktur, jika kata kunci tertentu selalu muncul setelah kata kunci lainnya, itu akan memberi Anda lebih banyak petunjuk. Tapi itu juga akan jauh lebih sulit untuk dirancang dan diterapkan.
Alternatifnya adalah dengan menggunakan highlight.js , yang melakukan penyorotan sintaks tetapi menggunakan tingkat keberhasilan proses penyorotan untuk mengidentifikasi bahasa. Pada prinsipnya, basis kode penyorot sintaks apa pun dapat digunakan dengan cara yang sama, tetapi hal yang menyenangkan tentang highlight.js adalah bahwa deteksi bahasa dianggap sebagai fitur dan digunakan untuk tujuan pengujian .
UPDATE: Saya mencoba ini dan tidak berhasil dengan baik. JavaScript yang dikompresi benar-benar membingungkannya, yaitu tokenizer peka spasi putih. Umumnya, hanya menghitung hit sorotan tampaknya tidak terlalu dapat diandalkan. Pengurai yang lebih kuat, atau mungkin jumlah bagian yang tidak cocok, mungkin bekerja lebih baik.
Pertama, saya akan mencoba menemukan kunci spesifik dari suatu bahasa misalnya
"package, class, implements "=> JAVA
"<?php " => PHP
"include main fopen strcmp stdout "=>C
"cout"=> C++
etc...
Itu akan tergantung pada jenis cuplikan yang Anda miliki, tetapi saya akan menjalankannya melalui serangkaian tokenizers dan melihat BNF bahasa mana yang valid.
Teka-teki yang bagus.
Saya pikir tidak mungkin untuk mendeteksi semua bahasa. Tapi Anda bisa memicu token kunci. (kata-kata tertentu yang dipesan dan kombinasi karakter yang sering digunakan).
Ben ada banyak bahasa dengan sintaks yang mirip. Jadi itu tergantung pada ukuran potongannya.
Prettify adalah paket Javascript yang berfungsi baik dalam mendeteksi bahasa pemrograman:
http://code.google.com/p/google-code-prettify/
Ini terutama penyorot sintaks, tetapi mungkin ada cara untuk mengekstrak bagian deteksi untuk tujuan mendeteksi bahasa dari cuplikan.
Saya membutuhkan ini jadi saya membuatnya sendiri. https://github.com/bertyhell/CodeClassifier
Ini sangat mudah diperpanjang dengan menambahkan file pelatihan di folder yang benar. Ditulis dalam c #. Tapi saya membayangkan kodenya mudah diubah ke bahasa lain.
Saya tidak berpikir akan ada cara mudah untuk mencapai ini. Saya mungkin akan membuat daftar simbol / kata kunci umum yang unik untuk bahasa / kelas bahasa tertentu (misalnya tanda kurung kurawal untuk bahasa C-style, kata kunci Dim dan Sub untuk bahasa BASIC, kata kunci def untuk Python, kata kunci let untuk bahasa fungsional) . Anda kemudian mungkin dapat menggunakan fitur sintaks dasar untuk mempersempitnya lebih jauh.
Saya pikir perbedaan terbesar antara bahasa adalah strukturnya. Jadi ide saya adalah melihat elemen umum tertentu di semua bahasa dan melihat perbedaannya. Misalnya, Anda dapat menggunakan ekspresi reguler untuk memilih hal-hal seperti:
Dan mungkin beberapa hal lain yang seharusnya dimiliki sebagian besar bahasa. Kemudian gunakan sistem poin. Berikan maksimal 1 poin untuk setiap elemen jika regex ditemukan. Jelas, beberapa bahasa akan menggunakan sintaks yang sama persis (untuk loop sering ditulis sepertifor(int i=0; i<x; ++i)
sedemikian rupa sehingga beberapa bahasa masing-masing dapat memberi skor satu poin untuk hal yang sama, tetapi setidaknya Anda mengurangi kemungkinannya menjadi bahasa yang sama sekali berbeda). Beberapa dari mereka mungkin mendapat skor 0s di seluruh papan (cuplikan tidak berisi fungsi sama sekali, misalnya) tapi itu tidak masalah.
Gabungkan ini dengan solusi Jules, dan ini akan bekerja dengan baik. Mungkin juga mencari frekuensi kata kunci untuk poin tambahan.
Menarik. Saya memiliki tugas serupa untuk mengenali teks dalam format berbeda. Properti YAML, JSON, XML, atau Java? Bahkan dengan kesalahan sintaks, misalnya, saya harus membedakan JSON dari XML dengan yakin.
Saya pikir bagaimana kita memodelkan masalah itu penting. Seperti yang dikatakan Mark, tokenisasi satu kata diperlukan tetapi kemungkinan tidak cukup. Kami membutuhkan bigram, atau bahkan trigram. Tapi saya pikir kita bisa melangkah lebih jauh dari sana dengan mengetahui bahwa kita sedang mempelajari bahasa pemrograman. Saya perhatikan bahwa hampir semua bahasa pemrograman memiliki dua jenis token unik - simbol dan kata kunci . Simbol relatif mudah (beberapa simbol mungkin literal bukan bagian dari bahasa) untuk dikenali. Kemudian bigram atau trigram simbol akan mengambil struktur sintaks unik di sekitar simbol. Kata kunci adalah sasaran empuk lain jika set pelatihan besar dan cukup beragam. Fitur yang berguna bisa berupa bigram seputar kemungkinan kata kunci. Jenis token lain yang menarik adalah spasi. Sebenarnya jika kita melakukan tokenisasi dengan cara biasa dengan spasi, kita akan kehilangan informasi ini. Saya akan mengatakan, untuk menganalisis bahasa pemrograman, kami menyimpan token spasi karena ini dapat membawa informasi berguna tentang struktur sintaks.
Akhirnya jika saya memilih pengklasifikasi seperti hutan acak, saya akan merayapi github dan mengumpulkan semua kode sumber publik. Sebagian besar file kode sumber dapat diberi label dengan akhiran file. Untuk setiap file, saya akan membaginya secara acak di baris kosong menjadi potongan dengan berbagai ukuran. Saya kemudian akan mengekstrak fitur dan melatih pengklasifikasi menggunakan cuplikan berlabel. Setelah pelatihan selesai, pengklasifikasi dapat diuji presisi dan perolehannya.
Solusi terbaik yang saya temukan adalah menggunakan permata ahli bahasa di aplikasi Ruby on Rails. Ini semacam cara khusus untuk melakukannya, tetapi berhasil. Ini disebutkan di atas oleh @nisc tetapi saya akan memberi tahu Anda langkah-langkah tepat saya untuk menggunakannya. (Beberapa dari perintah baris perintah berikut khusus untuk ubuntu tetapi harus dengan mudah diterjemahkan ke OS lain)
Jika Anda memiliki aplikasi rails yang tidak keberatan Anda mainkan untuk sementara, buat file baru di dalamnya untuk memasukkan cuplikan kode yang dipermasalahkan. (Jika Anda belum memasang rel, ada panduan yang bagus di sini meskipun untuk ubuntu saya merekomendasikan ini . Kemudian jalankan rails new <name-your-app-dir>
dan cd ke direktori itu. Semua yang Anda butuhkan untuk menjalankan aplikasi rel sudah ada di sana).
Setelah Anda memiliki aplikasi rel untuk menggunakan ini, tambahkan gem 'github-linguist'
ke Gemfile Anda (secara harfiah baru saja dipanggil Gemfile
di direktori aplikasi Anda, tidak ada ext).
Kemudian instal ruby-dev ( sudo apt-get install ruby-dev
)
Kemudian instal cmake ( sudo apt-get install cmake
)
Sekarang Anda dapat menjalankan gem install github-linguist
(jika Anda mendapatkan kesalahan yang mengatakan icu diperlukan, lakukan sudo apt-get install libicu-dev
dan coba lagi)
(Anda mungkin perlu melakukan sudo apt-get update
atau sudo apt-get install make
atau sudo apt-get install build-essential
jika cara di atas tidak berhasil)
Sekarang semuanya sudah diatur. Anda sekarang dapat menggunakan ini kapan saja Anda ingin memeriksa cuplikan kode. Di editor teks, buka file yang telah Anda buat untuk menyisipkan cuplikan kode Anda (anggap saja, app/test.tpl
tetapi jika mengetahui ekstensi dari cuplikan Anda, gunakan itu sebagai gantinya .tpl
. Jika Anda tidak tahu ekstensinya, jangan gunakan salah satu ). Sekarang tempel cuplikan kode Anda di file ini. Buka baris perintah dan jalankan bundle install
(harus ada di direktori aplikasi Anda). Kemudian jalankan linguist app/test.tpl
(lebih umum linguist <path-to-code-snippet-file>
). Ini akan memberi tahu Anda jenis, jenis pantomim, dan bahasa. Untuk banyak file (atau untuk penggunaan umum dengan aplikasi ruby / rails) Anda dapat menjalankannya bundle exec linguist --breakdown
di direktori aplikasi Anda.
Sepertinya banyak pekerjaan ekstra, terutama jika Anda belum memiliki rel, tetapi Anda sebenarnya tidak perlu tahu APA PUN tentang rel jika Anda mengikuti langkah-langkah ini dan saya benar-benar belum menemukan cara yang lebih baik untuk mendeteksi rel bahasa dari sebuah file / potongan kode.
Saya percaya bahwa tidak ada solusi tunggal yang mungkin dapat mengidentifikasi bahasa apa yang digunakan cuplikan, hanya berdasarkan cuplikan tunggal tersebut. Ambil kata kuncinya print
. Itu bisa muncul dalam sejumlah bahasa, yang masing-masing untuk tujuan yang berbeda, dan memiliki sintaks yang berbeda.
Saya punya beberapa nasihat. Saat ini saya sedang menulis sepotong kecil kode untuk situs web saya yang dapat digunakan untuk mengidentifikasi bahasa pemrograman. Seperti kebanyakan posting lainnya, mungkin ada banyak sekali bahasa pemrograman yang belum pernah Anda dengar, Anda tidak dapat menjelaskan semuanya.
Apa yang telah saya lakukan adalah setiap bahasa dapat diidentifikasi dengan pemilihan kata kunci. Misalnya, Python dapat diidentifikasi dengan berbagai cara. Mungkin lebih mudah jika Anda memilih 'ciri-ciri' yang juga pasti unik untuk bahasa tersebut. Untuk Python, saya memilih sifat menggunakan titik dua untuk memulai serangkaian pernyataan, yang menurut saya merupakan sifat yang cukup unik (perbaiki saya jika saya salah).
Jika, dalam contoh saya, Anda tidak dapat menemukan titik dua untuk memulai kumpulan pernyataan, kemudian pindah ke sifat lain yang mungkin, katakanlah menggunakan def
kata kunci untuk mendefinisikan fungsi. Sekarang ini bisa menyebabkan beberapa masalah, karena Ruby juga menggunakan kata kunci def
untuk mendefinisikan suatu fungsi. Kunci untuk membedakan keduanya (Python dan Ruby) adalah dengan menggunakan berbagai level pemfilteran untuk mendapatkan kecocokan terbaik. Ruby menggunakan kata kunci end
untuk menyelesaikan suatu fungsi, sedangkan Python tidak memiliki apa pun untuk menyelesaikan suatu fungsi, hanya sebuah de-indentasi tetapi Anda tidak ingin pergi ke sana. Tapi lagi,end
bisa juga Lua, bahasa pemrograman lain untuk ditambahkan ke dalam campuran.
Anda dapat melihat bahwa bahasa pemrograman terlalu banyak menutupi. Satu kata kunci yang bisa menjadi kata kunci dalam satu bahasa bisa menjadi kata kunci dalam bahasa lain. Menggunakan kombinasi kata kunci yang sering kali digabungkan, seperti Javapublic static void main(String[] args)
membantu menghilangkan masalah tersebut.
Seperti yang telah saya katakan sebelumnya, peluang terbaik Anda adalah mencari kata kunci yang relatif unik atau kumpulan kata kunci untuk memisahkan satu dari yang lain. Dan, jika Anda salah, setidaknya Anda mencobanya.
Situs ini tampaknya cukup bagus dalam mengidentifikasi bahasa, jika Anda menginginkan cara cepat untuk menempelkan potongan ke dalam formulir web, daripada melakukannya secara terprogram: http://dpaste.com/