วิธีใดเป็นวิธีที่ดีที่สุดในการตรวจสอบว่าภาษาโปรแกรมที่ใช้ในข้อมูลโค้ดคืออะไร
วิธีใดเป็นวิธีที่ดีที่สุดในการตรวจสอบว่าภาษาโปรแกรมที่ใช้ในข้อมูลโค้ดคืออะไร
คำตอบ:
ฉันคิดว่าวิธีที่ใช้ในตัวกรองสแปมจะได้ผลดี คุณแยกข้อมูลโค้ดออกเป็นคำ จากนั้นคุณเปรียบเทียบการเกิดขึ้นของคำเหล่านี้กับตัวอย่างข้อมูลที่ทราบแล้วคำนวณความน่าจะเป็นที่ตัวอย่างข้อมูลนี้เขียนด้วยภาษา X สำหรับทุกภาษาที่คุณสนใจ
http://en.wikipedia.org/wiki/Bayesian_spam_filtering
หากคุณมีกลไกพื้นฐานการเพิ่มภาษาใหม่ก็ทำได้ง่ายมากเพียงฝึกเครื่องมือตรวจจับด้วยตัวอย่างข้อมูลบางส่วนในภาษาใหม่ (คุณสามารถป้อนข้อมูลให้เป็นโครงการโอเพ่นซอร์สได้) วิธีนี้ทำให้ทราบว่า "ระบบ" มีแนวโน้มที่จะปรากฏในข้อมูลโค้ด C # และ "ใส่" ในข้อมูลโค้ด Ruby
ฉันเคยใช้วิธีนี้เพื่อเพิ่มการตรวจจับภาษาลงในข้อมูลโค้ดสำหรับซอฟต์แวร์ฟอรัม มันทำงานได้ 100% ของเวลายกเว้นในกรณีที่ไม่ชัดเจน:
print "Hello"
ให้ฉันหารหัส
ฉันไม่พบรหัสดังนั้นฉันจึงสร้างรหัสใหม่ มันค่อนข้างง่าย แต่ใช้ได้กับการทดสอบของฉัน ปัจจุบันหากคุณป้อนรหัส Python มากกว่ารหัส Ruby ก็น่าจะบอกได้ว่ารหัสนี้:
def foo
puts "hi"
end
คือรหัส Python (แม้ว่าจะเป็น Ruby ก็ตาม) เนื่องจาก Python มีdef
คีย์เวิร์ดด้วย ดังนั้นหากมันเห็น 1000x def
ใน Python และ 100x def
ใน Ruby มันอาจจะยังพูดว่า Python แม้ว่าputs
และend
เป็นทับทิมที่เฉพาะเจาะจง คุณสามารถแก้ไขปัญหานี้ได้โดยการติดตามคำที่เห็นต่อภาษาและหารด้วยที่ใดที่หนึ่ง (หรือป้อนรหัสจำนวนเท่า ๆ กันในแต่ละภาษา)
ฉันหวังว่ามันจะช่วยคุณ:
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)
$
ดังนั้นคุณไม่ควรแบ่งขอบเขตของคำเพราะ$
ตัวแปรควรยึดติดกับตัวแปร ตัวดำเนินการชอบ=>
และ:=
ควรจะติดกันเป็นโทเค็นเดียว แต่ OTH คุณควรแยกออกจากกัน{
เพราะพวกเขามักจะยืนหยัดด้วยตัวเอง
การตรวจจับภาษาแก้ไขโดยผู้อื่น:
แนวทางของ Ohloh: https://github.com/blackducksw/ohcount/
แนวทางของ Github: https://github.com/github/linguist
คุณอาจพบว่าวัสดุที่มีประโยชน์บางอย่างที่นี่: http://alexgorbatchev.com/wiki/SyntaxHighlighter Alex ใช้เวลาส่วนใหญ่ในการหาวิธีแยกวิเคราะห์ภาษาต่างๆจำนวนมากและองค์ประกอบทางไวยากรณ์ที่สำคัญคืออะไร
Guesslang เป็นทางออกที่เป็นไปได้:
http://guesslang.readthedocs.io/en/latest/index.html
นอกจากนี้ยังมี SourceClassifier:
https://github.com/chrislo/sourceclassifier/tree/master
ฉันสนใจปัญหานี้หลังจากพบโค้ดบางส่วนในบทความบล็อกซึ่งฉันไม่สามารถระบุได้ การเพิ่มคำตอบนี้เนื่องจากคำถามนี้เป็นการค้นหาครั้งแรกสำหรับ "ระบุภาษาโปรแกรม"
มันยากมากและบางครั้งก็เป็นไปไม่ได้ ตัวอย่างข้อมูลสั้น ๆ นี้มาจากภาษาใด
int i = 5;
int k = 0;
for (int j = 100 ; j > i ; i++) {
j = j + 1000 / i;
k = k + i * j;
}
(คำแนะนำ: อาจเป็นอย่างใดอย่างหนึ่งจากหลาย ๆ อันก็ได้)
คุณสามารถลองวิเคราะห์ภาษาต่างๆและลองตัดสินใจโดยใช้การวิเคราะห์ความถี่ของคำหลัก หากคำหลักบางชุดเกิดขึ้นพร้อมกับความถี่บางอย่างในข้อความอาจเป็นไปได้ว่าภาษานั้นเป็น Java เป็นต้น แต่ฉันไม่คิดว่าคุณจะได้รับสิ่งใดที่เป็นหลักฐานหลอกอย่างสมบูรณ์เนื่องจากคุณสามารถตั้งชื่อตัวแปรใน C ชื่อเดียวกันได้ เป็นคีย์เวิร์ดใน Java และการวิเคราะห์ความถี่จะถูกหลอก
หากคุณเข้าใจถึงความซับซ้อนคุณสามารถมองหาโครงสร้างได้หากคำหลักบางคำมาจากคำอื่นเสมอนั่นจะทำให้คุณได้เบาะแสมากขึ้น แต่จะยากกว่ามากในการออกแบบและใช้งาน
อีกทางเลือกหนึ่งคือการใช้highlight.jsซึ่งทำการไฮไลต์ไวยากรณ์ แต่ใช้อัตราความสำเร็จของกระบวนการไฮไลต์เพื่อระบุภาษา ในหลักการใด ๆ codebase ไวยากรณ์เน้นสามารถนำมาใช้ในทางเดียวกัน แต่สิ่งที่ดีเกี่ยวกับการ highlight.js คือการตรวจหาภาษาถือว่าเป็นคุณลักษณะและถูกนำมาใช้เพื่อวัตถุประสงค์ในการทดสอบ
UPDATE:ฉันลองแล้ว แต่มันไม่ได้ผล JavaScript ที่บีบอัดทำให้สับสนโดยสิ้นเชิงกล่าวคือโทเค็นมีความไวต่อช่องว่าง โดยทั่วไปแล้วการนับเฉพาะไฮไลต์ยอดนิยมดูเหมือนจะไม่น่าเชื่อถือ ตัวแยกวิเคราะห์ที่แข็งแกร่งกว่าหรืออาจมีจำนวนส่วนที่ไม่ตรงกันอาจทำงานได้ดีกว่า
ก่อนอื่นฉันจะพยายามค้นหาคีย์เวิร์คเฉพาะของภาษาเช่น
"package, class, implements "=> JAVA
"<?php " => PHP
"include main fopen strcmp stdout "=>C
"cout"=> C++
etc...
มันจะขึ้นอยู่กับประเภทของข้อมูลโค้ดที่คุณมี แต่ฉันจะเรียกใช้ผ่านชุดโทเค็นไนเซอร์และดูว่า BNF ของภาษาใดที่ใช้กับภาษาได้
ปริศนาที่ดี
ฉันคิดว่ามันเป็นไปไม่ได้ที่จะตรวจพบทุกภาษา แต่คุณสามารถเรียกใช้โทเค็นหลักได้ (คำสงวนบางคำและมักใช้การผสมอักขระ)
Ben มีหลายภาษาที่มีไวยากรณ์คล้ายกัน ดังนั้นจึงขึ้นอยู่กับขนาดของข้อมูลโค้ด
Prettify เป็นแพ็คเกจ Javascript ที่ตรวจจับภาษาโปรแกรมได้อย่างถูกต้อง:
http://code.google.com/p/google-code-prettify/
ส่วนใหญ่เป็นเครื่องมือเน้นไวยากรณ์ แต่อาจมีวิธีแยกส่วนการตรวจจับเพื่อวัตถุประสงค์ในการตรวจจับภาษาจากตัวอย่างข้อมูล
ฉันต้องการสิ่งนี้ดังนั้นฉันจึงสร้างของฉันเอง https://github.com/bertyhell/CodeClassifier
สามารถขยายได้ง่ายมากโดยการเพิ่มไฟล์การฝึกอบรมในโฟลเดอร์ที่ถูกต้อง เขียนใน c #. แต่ฉันคิดว่าโค้ดสามารถแปลงเป็นภาษาอื่นได้อย่างง่ายดาย
ฉันไม่คิดว่าจะมีวิธีง่ายๆในการทำสิ่งนี้ให้สำเร็จ ฉันอาจจะสร้างรายการสัญลักษณ์ / คำหลักทั่วไปที่ไม่ซ้ำกับภาษา / คลาสของภาษาบางภาษา (เช่นวงเล็บปีกกาสำหรับภาษาสไตล์ C คำหลัก Dim และ Sub สำหรับภาษาพื้นฐานคำหลัก def สำหรับ Python คำหลัก let สำหรับภาษาที่ใช้งานได้) . จากนั้นคุณอาจสามารถใช้คุณสมบัติไวยากรณ์พื้นฐานเพื่อ จำกัด ขอบเขตให้แคบลงได้อีก
ฉันคิดว่าความแตกต่างที่ใหญ่ที่สุดระหว่างภาษาคือโครงสร้างของมัน ดังนั้นความคิดของฉันคือการดูองค์ประกอบทั่วไปบางอย่างในทุกภาษาและดูว่ามันแตกต่างกันอย่างไร ตัวอย่างเช่นคุณสามารถใช้ regexes เพื่อเลือกสิ่งต่างๆเช่น:
และอาจมีสิ่งอื่น ๆ อีกเล็กน้อยที่ภาษาส่วนใหญ่ควรมี จากนั้นใช้ระบบจุด ให้รางวัลสูงสุด 1 คะแนนสำหรับแต่ละองค์ประกอบหากพบ regex เห็นได้ชัดว่าบางภาษาจะใช้ไวยากรณ์เดียวกันทุกประการ (สำหรับลูปมักจะเขียนเหมือนกันfor(int i=0; i<x; ++i)
เพื่อให้แต่ละภาษาได้คะแนนสำหรับสิ่งเดียวกัน แต่อย่างน้อยคุณก็ลดโอกาสที่จะเป็นภาษาที่แตกต่างกันโดยสิ้นเชิง) บางคนอาจได้คะแนน 0 ทั้งกระดาน (ตัวอย่างข้อมูลไม่มีฟังก์ชันเลย) แต่ก็ใช้ได้ดี
รวมสิ่งนี้เข้ากับโซลูชันของ Jules และควรใช้งานได้ดี อาจมองหาความถี่ของคำหลักเพื่อจุดพิเศษ
น่าสนใจ ฉันมีภารกิจที่คล้ายกันในการจดจำข้อความในรูปแบบต่างๆ คุณสมบัติ YAML, JSON, XML หรือ Java? ตัวอย่างเช่นแม้จะมีข้อผิดพลาดทางไวยากรณ์ฉันควรแยก JSON ออกจาก XML ด้วยความมั่นใจ
ฉันคิดว่าเราจำลองปัญหานั้นสำคัญอย่างไร ดังที่ Mark กล่าวว่าการสร้างโทเค็นคำเดียวเป็นสิ่งที่จำเป็น แต่น่าจะไม่เพียงพอ เราจะต้องใช้ bigrams หรือแม้แต่ trigrams แต่ฉันคิดว่าเราสามารถไปได้ไกลกว่านั้นโดยรู้ว่าเรากำลังมองหาภาษาโปรแกรม ผมสังเกตเห็นว่าเกือบทุกภาษาโปรแกรมที่มีสองประเภทที่ไม่ซ้ำกันของสัญญาณ - สัญลักษณ์และคำหลัก สัญลักษณ์นั้นค่อนข้างง่าย (สัญลักษณ์บางตัวอาจเป็นตัวอักษรไม่ใช่ส่วนหนึ่งของภาษา) ที่จะจดจำ จากนั้นสัญลักษณ์ bigrams หรือตรีโกณมิติจะรับโครงสร้างไวยากรณ์ที่ไม่ซ้ำกันรอบ ๆ สัญลักษณ์ คีย์เวิร์ดเป็นอีกหนึ่งเป้าหมายที่ง่ายหากชุดฝึกมีขนาดใหญ่และมีความหลากหลายเพียงพอ คุณลักษณะที่มีประโยชน์อาจเป็นตัวใหญ่รอบคำหลักที่เป็นไปได้ โทเค็นอีกประเภทที่น่าสนใจคือช่องว่าง. จริงๆแล้วถ้าเราสร้างโทเค็นตามปกติด้วยช่องว่างเราจะทำให้ข้อมูลนี้หลุดออกไป ฉันจะบอกว่าสำหรับการวิเคราะห์ภาษาโปรแกรมเราเก็บโทเค็นช่องว่างไว้เนื่องจากอาจมีข้อมูลที่เป็นประโยชน์เกี่ยวกับโครงสร้างไวยากรณ์
ในที่สุดถ้าฉันเลือกลักษณนามเช่นฟอเรสต์สุ่มฉันจะรวบรวมข้อมูล github และรวบรวมซอร์สโค้ดสาธารณะทั้งหมด ไฟล์ซอร์สโค้ดส่วนใหญ่สามารถติดป้ายกำกับด้วยคำต่อท้ายไฟล์ สำหรับแต่ละไฟล์ฉันจะสุ่มแยกในบรรทัดว่างเป็นตัวอย่างขนาดต่างๆ จากนั้นฉันจะแยกคุณสมบัติและฝึกลักษณนามโดยใช้ตัวอย่างข้อมูลที่มีป้ายกำกับ หลังจากการฝึกเสร็จสิ้นสามารถทดสอบลักษณนามเพื่อความแม่นยำและเรียกคืนได้
ทางออกที่ดีที่สุดที่ฉันเจอคือการใช้อัญมณีนักภาษาในแอป Ruby on Rails เป็นวิธีที่เฉพาะเจาะจง แต่ได้ผล สิ่งนี้ถูกกล่าวถึงข้างต้นโดย @nisc แต่ฉันจะบอกขั้นตอนที่แน่นอนในการใช้งาน (คำสั่งบรรทัดคำสั่งต่อไปนี้บางคำสั่งเฉพาะสำหรับ ubuntu แต่ควรแปลเป็นระบบปฏิบัติการอื่นได้อย่างง่ายดาย)
หากคุณมีแอพพลิเคชั่นรางที่คุณไม่คิดจะยุ่งกับมันชั่วคราวให้สร้างไฟล์ใหม่ในแอพเพื่อใส่ข้อมูลโค้ดที่มีปัญหา (หากคุณไม่ได้ติดตั้งรางมีคำแนะนำที่ดีที่นี่แม้ว่าสำหรับ ubuntu ฉันขอแนะนำสิ่งนี้จากนั้นเรียกใช้rails new <name-your-app-dir>
และ cd ลงในไดเร็กทอรีนั้นทุกสิ่งที่คุณต้องการในการเรียกใช้แอพ rail มีอยู่แล้ว)
หลังจากที่คุณมีแอปพลิเคชันรางที่จะใช้กับสิ่งนี้แล้วให้เพิ่มลงgem 'github-linguist'
ใน Gemfile ของคุณ (เรียกตามตัวอักษรGemfile
ในไดเรกทอรีแอปของคุณเท่านั้นไม่มีส่วนต่อขยาย)
จากนั้นติดตั้ง Ruby-dev ( sudo apt-get install ruby-dev
)
จากนั้นติดตั้ง cmake ( sudo apt-get install cmake
)
ตอนนี้คุณสามารถเรียกใช้gem install github-linguist
(หากคุณได้รับข้อผิดพลาดที่ระบุว่าต้องใช้ icu ให้ทำsudo apt-get install libicu-dev
และลองอีกครั้ง)
(คุณอาจต้องทำsudo apt-get update
หรือsudo apt-get install make
หรือsudo apt-get install build-essential
ถ้าข้างต้นไม่ได้ทำงาน)
ตอนนี้ทุกอย่างถูกตั้งค่าแล้ว ตอนนี้คุณสามารถใช้สิ่งนี้ได้ทุกเมื่อที่ต้องการตรวจสอบข้อมูลโค้ด ในโปรแกรมแก้ไขข้อความให้เปิดไฟล์ที่คุณสร้างขึ้นเพื่อแทรกข้อมูลโค้ดของคุณ (สมมติว่าเป็นapp/test.tpl
แต่ถ้าทราบส่วนขยายของข้อมูลโค้ดของคุณให้ใช้แทน.tpl
หากคุณไม่ทราบส่วนขยายอย่าใช้ส่วนขยาย ) ตอนนี้วางข้อมูลโค้ดของคุณในไฟล์นี้ ไปที่บรรทัดคำสั่งและเรียกใช้bundle install
(ต้องอยู่ในไดเร็กทอรีของแอปพลิเคชันของคุณ) จากนั้นเรียกใช้linguist app/test.tpl
(โดยทั่วไปlinguist <path-to-code-snippet-file>
) มันจะบอกประเภทประเภทละครใบ้และภาษา สำหรับไฟล์หลายไฟล์ (หรือสำหรับการใช้งานทั่วไปกับแอพ Ruby / Rails) คุณสามารถเรียกใช้bundle exec linguist --breakdown
ในไดเร็กทอรีของแอปพลิเคชันของคุณ
ดูเหมือนว่าจะต้องทำงานพิเศษมากมายโดยเฉพาะอย่างยิ่งถ้าคุณยังไม่มีราง แต่คุณไม่จำเป็นต้องรู้อะไรเกี่ยวกับรางถ้าคุณทำตามขั้นตอนเหล่านี้และฉันก็ไม่พบวิธีที่ดีกว่าในการตรวจจับ ภาษาของไฟล์ / ข้อมูลโค้ด
ฉันเชื่อว่าไม่มีวิธีแก้ปัญหาเดียวที่สามารถระบุได้ว่าข้อมูลโค้ดอยู่ในภาษาใดโดยพิจารณาจากตัวอย่างข้อมูลเดียวนั้น ใช้คำหลักprint
ใช้คำหลักอาจปรากฏในหลายภาษาซึ่งแต่ละภาษามีวัตถุประสงค์ที่แตกต่างกันและมีไวยากรณ์ที่แตกต่างกัน
ฉันมีคำแนะนำ ฉันกำลังเขียนโค้ดชิ้นเล็ก ๆ สำหรับเว็บไซต์ของฉันซึ่งสามารถใช้ระบุภาษาโปรแกรมได้ เช่นเดียวกับโพสต์อื่น ๆ ส่วนใหญ่อาจมีขนาดใหญ่ช่วงของการเขียนโปรแกรมภาษาที่คุณก็ยังไม่เคยได้ยินคุณไม่สามารถบัญชีสำหรับพวกเขาทั้งหมด
สิ่งที่ฉันทำคือแต่ละภาษาสามารถระบุได้ด้วยคำหลักที่เลือก ตัวอย่างเช่น Python สามารถระบุได้หลายวิธี อาจจะง่ายกว่าถ้าคุณเลือก "ลักษณะ" ที่เป็นเอกลักษณ์ของภาษานั้น ๆ สำหรับ Python ฉันเลือกลักษณะของการใช้โคลอนเพื่อเริ่มชุดคำสั่งซึ่งฉันเชื่อว่าเป็นลักษณะเฉพาะที่ไม่เหมือนใคร (แก้ไขฉันถ้าฉันผิด)
ถ้าในตัวอย่างของฉันคุณไม่พบเครื่องหมายจุดคู่เพื่อเริ่มชุดคำสั่งจากนั้นย้ายไปยังลักษณะอื่นที่เป็นไปได้สมมติว่าใช้ def
คีย์เวิร์ดเพื่อกำหนดฟังก์ชัน ตอนนี้อาจทำให้เกิดปัญหาบางอย่างได้เนื่องจาก Ruby ยังใช้คำหลักdef
เพื่อกำหนดฟังก์ชัน กุญแจสำคัญในการแยกทั้งสอง (Python และ Ruby) คือการใช้การกรองระดับต่างๆเพื่อให้ได้คู่ที่ดีที่สุด Ruby ใช้คีย์เวิร์ดend
เพื่อจบฟังก์ชั่นในขณะที่ Python ไม่มีอะไรที่จะทำให้ฟังก์ชั่นเสร็จสิ้นเพียงแค่การเยื้อง แต่คุณไม่ต้องการไปที่นั่น แต่อีกครั้งend
อาจเป็น Lua แต่เป็นภาษาโปรแกรมอื่นที่จะเพิ่มลงในส่วนผสม
คุณจะเห็นได้ว่าภาษาโปรแกรมนั้นซ้อนทับกันมากเกินไป คำหลักหนึ่งคำที่อาจเป็นคำหลักในภาษาหนึ่งอาจเป็นคำหลักในภาษาอื่น การใช้คีย์เวิร์ดที่มักจะไปด้วยกันเช่น Java public static void main(String[] args)
ช่วยขจัดปัญหาเหล่านั้น
อย่างที่ฉันได้กล่าวไปแล้วโอกาสที่ดีที่สุดของคุณคือการมองหาคำหลักหรือชุดคำหลักที่ไม่ซ้ำใครเพื่อแยกคำหลักออกจากคำอื่น และถ้าคุณเข้าใจผิดอย่างน้อยคุณก็ได้ไป
ตั้งค่า scrambler แบบสุ่มเช่น
matrix S = matrix(GF(2),k,[random()<0.5for _ in range(k^2)]); while (rank(S) < k) : S[floor(k*random()),floor(k*random())] +=1;
ดูเหมือนว่าไซต์นี้จะระบุภาษาได้ค่อนข้างดีหากคุณต้องการวิธีที่รวดเร็วในการวางตัวอย่างข้อมูลลงในแบบฟอร์มบนเว็บแทนที่จะทำโดยใช้โปรแกรม: http://dpaste.com/