코드 스 니펫에서 사용되는 프로그래밍 언어를 감지하는 가장 좋은 방법은 무엇입니까?
코드 스 니펫에서 사용되는 프로그래밍 언어를 감지하는 가장 좋은 방법은 무엇입니까?
답변:
스팸 필터에 사용되는 방법이 아주 잘 작동 할 것이라고 생각합니다. 스 니펫을 단어로 분할합니다. 그런 다음이 단어의 발생을 알려진 스 니펫과 비교하고 관심있는 모든 언어에 대해이 스 니펫이 언어 X로 작성 될 확률을 계산합니다.
http://en.wikipedia.org/wiki/Bayesian_spam_filtering
기본 메커니즘이있는 경우 새 언어를 추가하는 것은 매우 쉽습니다. 새 언어로 된 몇 개의 스 니펫으로 감지기를 훈련시키기 만하면됩니다 (오픈 소스 프로젝트에 피드 할 수 있음). 이렇게하면 "System"이 C # 스 니펫에 나타나고 Ruby 스 니펫에 "puts"가 나타날 가능성이 있다는 것을 알게됩니다.
실제로이 방법을 사용하여 포럼 소프트웨어 용 코드 조각에 언어 감지를 추가했습니다. 모호한 경우를 제외하고는 100 % 작동했습니다.
print "Hello"
코드를 찾아 보겠습니다.
코드를 찾을 수 없어서 새로 만들었습니다. 약간 단순하지만 내 테스트에서 작동합니다. 현재 Ruby 코드보다 훨씬 더 많은 Python 코드를 제공하면 다음 코드가 표시 될 수 있습니다.
def foo
puts "hi"
end
파이썬 코드입니다 (실제로 루비 임에도 불구하고). 파이썬에도 def
키워드 가 있기 때문 입니다. 이 1000X 보았다 그렇다면 def
파이썬과 100 배 def
루비를 다음 여전히 비록 파이썬을 말할 수 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
나는 블로그 기사에서 내가 식별 할 수없는 코드를 찾은 후에이 문제에 관심을 갖게되었다. 이 질문이 "identify programming language"에 대한 첫 번째 검색 히트 였으므로이 답변을 추가했습니다.
매우 어렵고 때로는 불가능합니다. 이 짧은 스 니펫은 어떤 언어에서 왔습니까?
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 수행 구문 강조하지만, 언어를 식별하기 위해 강조 프로세스의 성공 속도를 사용합니다. 원칙적으로 모든 구문 하이 라이터 코드베이스는 동일한 방식으로 사용될 수 있지만 highlight.js의 좋은 점은 언어 감지가 기능으로 간주되고 테스트 목적으로 사용 된다는 것입니다. 입니다.
업데이트 : 나는 이것을 시도했지만 잘 작동하지 않았습니다. 압축 된 JavaScript는 완전히 혼란 스러웠습니다. 즉 토크 나이 저는 공백에 민감합니다. 일반적으로 하이라이트 히트 수를 계산하는 것은 그다지 신뢰할 수없는 것 같습니다. 더 강력한 구문 분석기 또는 일치하지 않는 섹션 수가 더 잘 작동 할 수 있습니다.
Prettify는 프로그래밍 언어를 감지하는 데 적합한 Javascript 패키지입니다.
http://code.google.com/p/google-code-prettify/
주로 구문 하이 라이터이지만 스 니펫에서 언어를 감지하기 위해 감지 부분을 추출하는 방법이있을 수 있습니다.
나는 이것을 필요로 했으므로 내 자신을 만들었습니다. https://github.com/bertyhell/CodeClassifier
올바른 폴더에 교육 파일을 추가하여 매우 쉽게 확장 할 수 있습니다. C #으로 작성되었습니다. 그러나 코드가 다른 언어로 쉽게 변환 될 것이라고 생각합니다.
언어의 가장 큰 차이점은 구조라고 생각합니다. 그래서 제 생각은 모든 언어에서 공통적 인 요소를 살펴보고 어떻게 다른지 보는 것입니다. 예를 들어 정규식을 사용하여 다음과 같은 항목을 선택할 수 있습니다.
그리고 아마도 대부분의 언어가 가져야 할 몇 가지 다른 것들이 있습니다. 그런 다음 포인트 시스템을 사용하십시오. 정규식이 발견되면 각 요소에 대해 최대 1 점을 부여합니다. 분명히 일부 언어는 똑같은 구문을 사용합니다 (for 루프는 종종 다음과 같이 작성됩니다.for(int i=0; i<x; ++i)
여러 언어가 대해 점수를 매길 수 있도록 되지만 적어도 완전히 다른 언어가 될 가능성을 줄입니다). 그들 중 일부는 전반적으로 0 점을 기록 할 수 있지만 (예를 들어 스 니펫에는 함수가 전혀 포함되어 있지 않음) 완벽하게 괜찮습니다.
이것을 Jules의 솔루션과 결합하면 꽤 잘 작동합니다. 추가 요점을 위해 키워드 빈도를 찾을 수도 있습니다.
흥미 롭군. 다른 형식의 텍스트를 인식하는 비슷한 작업이 있습니다. YAML, JSON, XML 또는 Java 속성? 예를 들어 구문 오류가 있어도 JSON과 XML을 확실하게 구분해야합니다.
문제를 모델링하는 방법이 중요하다고 생각합니다. Mark가 말했듯이 단일 단어 토큰 화가 필요하지만 충분하지 않을 수 있습니다. 우리는 bigrams 또는 심지어 trigrams가 필요할 것입니다. 그러나 나는 우리가 프로그래밍 언어를 찾고 있다는 것을 알면 거기에서 더 멀리 갈 수 있다고 생각합니다. 거의 모든 프로그래밍 언어에는 기호 와 키워드 라는 두 가지 고유 한 유형의 토큰이 있습니다. 기호는 비교적 쉽게 인식 할 수 있습니다 (일부 기호는 언어의 일부가 아닌 리터럴 일 수 있음). 그런 다음 기호의 바이그램 또는 트리 그램은 기호 주변의 고유 한 구문 구조를 선택합니다. 훈련 세트가 충분히 크고 다양한 경우 키워드는 또 다른 쉬운 목표입니다. 유용한 기능은 가능한 키워드에 대한 bigrams 일 수 있습니다. 또 다른 흥미로운 유형의 토큰은 공백입니다.. 실제로 일반적인 방식으로 공백으로 토큰 화하면이 정보가 손실됩니다. 프로그래밍 언어를 분석하기 위해 구문 구조에 대한 유용한 정보를 전달할 수 있으므로 공백 토큰을 유지합니다.
마지막으로 랜덤 포레스트와 같은 분류자를 선택하면 github를 크롤링하고 모든 공개 소스 코드를 수집합니다. 대부분의 소스 코드 파일은 파일 접미사로 레이블을 지정할 수 있습니다. 각 파일에 대해 빈 줄에서 무작위로 다양한 크기의 조각으로 분할합니다. 그런 다음 특성을 추출하고 레이블이 지정된 스 니펫을 사용하여 분류기를 훈련합니다. 훈련이 완료되면 분류기의 정밀도와 재현율을 테스트 할 수 있습니다.
내가 만난 최고의 솔루션 은 Ruby on Rails 앱에서 linguist gem 을 사용하는 것 입니다. 그것은 그것을하는 특정한 방법의 일종이지만 작동합니다. 이것은 위에서 @nisc에 의해 언급되었지만 정확한 사용 단계를 알려 드리겠습니다. (다음 명령 줄 명령 중 일부는 우분투에만 해당되지만 다른 OS로 쉽게 변환되어야합니다)
일시적으로 엉망이 되어도 괜찮은 Rails 앱이 있다면 그 안에 새 파일을 만들어 문제의 코드 스 니펫을 삽입하세요. (당신이없는 경우 레일은 좋은 가이드가있어 설치 여기 우분투 내가 추천하지만, 이 . 그런 다음 실행 rails new <name-your-app-dir>
하고 해당 디렉토리에 CD를 넣습니다. 모든 것이 실행할 필요가 앱이 이미 레일).
이것을 사용할 rails 앱이 gem 'github-linguist'
있으면 Gemfile에 추가 합니다 (문자 그대로 Gemfile
앱 디렉토리에서 호출 되며 ext가 없음).
그런 다음 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>
). 유형, MIME 유형 및 언어를 알려줍니다. 여러 파일의 경우 (또는 ruby / rails 앱에서 일반적으로 사용하는 경우) bundle exec linguist --breakdown
애플리케이션의 디렉토리에서 실행할 수 있습니다 .
특히 레일이 아직없는 경우에는 많은 추가 작업처럼 보이지만,이 단계를 따르면 레일에 대해 실제로 알 필요가 없습니다. 그리고 저는 실제로 레일을 감지하는 더 좋은 방법을 찾지 못했습니다. 파일 / 코드 조각의 언어.
나는 단지 하나의 스 니펫을 기반으로 스 니펫이 어떤 언어로되어 있는지 식별 할 수있는 단일 솔루션이 없다고 생각합니다. 키워드를 사용하십시오 print
. 여러 언어로 표시 될 수 있으며 각 언어는 용도가 다르고 구문도 다릅니다.
조언이 있습니다. 저는 현재 프로그래밍 언어를 식별하는 데 사용할 수있는 웹 사이트 용 코드를 작성하고 있습니다. 대부분의 다른 게시물과 마찬가지로 , 여러분이 듣지 못했던 프로그래밍 언어가 엄청나게 많을 수 있습니다 . 모두를 설명 할 수는 없습니다.
내가 한 것은 각 언어가 키워드 선택으로 식별 될 수 있다는 것입니다. 예를 들어, Python은 여러 가지 방법으로 식별 할 수 있습니다. 확실히 언어 고유의 '특성'을 선택하면 더 쉬울 것입니다. 파이썬의 경우 콜론을 사용하여 일련의 문을 시작하는 특성을 선택합니다. 이것은 상당히 독특한 특성이라고 생각합니다 (내가 틀렸다면 수정).
내 예에서 명령문 집합을 시작하는 콜론을 찾을 수없는 경우 가능한 다른 특성으로 이동 def
합니다. 키워드를 사용하여 함수를 정의 한다고 가정 해 보겠습니다 . 이제 Ruby가 키워드 def
를 사용하여 함수를 정의 하기 때문에 문제가 발생할 수 있습니다 . 둘 (Python과 Ruby)을 구분하는 핵심은 다양한 수준의 필터링을 사용하여 최상의 일치를 얻는 것입니다. Ruby는 키워드 end
를 사용하여 함수를 완료하는 반면 Python은 함수를 완료하는 데 아무 것도없고 들여 쓰기 만 취소하지만 거기에 가고 싶지 않습니다. 그러나 다시 말하지만, end
Lua가 될 수도 있습니다. 또 다른 프로그래밍 언어가 추가 될 수 있습니다.
프로그래밍 언어가 너무 많이 오버레이된다는 것을 알 수 있습니다. 한 언어의 키워드가 될 수있는 하나의 키워드가 다른 언어의 키워드 일 수 있습니다. Java와 같이 자주 함께 사용되는 키워드 조합을 사용 public static void main(String[] args)
하면 이러한 문제를 제거하는 데 도움이됩니다.
이미 말했듯이 가장 좋은 기회는 상대적으로 고유 한 키워드 또는 키워드 집합을 찾아서 서로 구분하는 것입니다. 그리고 만약 당신이 틀렸다면, 적어도 당신은 시도했습니다.
이 사이트는 프로그래밍 방식으로 수행하는 대신 웹 양식에 스 니펫을 빠르게 붙여 넣는 방법을 원할 경우 언어 식별에 매우 능숙한 것 같습니다. http://dpaste.com/