스 니펫에서 프로그래밍 언어 감지


115

코드 스 니펫에서 사용되는 프로그래밍 언어를 감지하는 가장 좋은 방법은 무엇입니까?


1
실제로 무한한 수의 언어가 있습니다 ... 그중 하나라도 감지 하시겠습니까? 아니면 우리는 단지 인기있는 것을 말하는 것입니까?
Spencer Ruport

인기있는 것 (C / C ++, C #, Java, Pascal, Python, VB.NET. PHP, JavaScript 및 Haskell) 만 있습니다.
João Matos

12
글쎄 Haskell은 내가 들어 본 적이 없기 때문에 인기가 없습니다. ;-)
Stephanie Page

22
Haskell에 대해 들어 보지 못했다면 프로그래밍 언어에 대해 많이 알지 못할 것입니다.
Akhorus 2015

4
그것을 수행이 온라인 서비스가 제공됩니다 : algorithmia.com/algorithms/PetiteProgrammer/...
베니 노이게 바우어

답변:


99

스팸 필터에 사용되는 방법이 아주 잘 작동 할 것이라고 생각합니다. 스 니펫을 단어로 분할합니다. 그런 다음이 단어의 발생을 알려진 스 니펫과 비교하고 관심있는 모든 언어에 대해이 스 니펫이 언어 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루비를 다음 여전히 비록 파이썬을 말할 수 putsend루비 다릅니다. 언어별로 표시되는 단어를 추적하고 어딘가로 나누어서 (또는 각 언어에 동일한 양의 코드를 제공하여)이 문제를 해결할 수 있습니다.

도움이 되었기를 바랍니다.

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)

1
포럼 소프트웨어에서도 사용해야합니다. 베이지안 필터링에 대한 팁을 주셔서 감사합니다.
João Matos

12
NLP 수업에서 이와 같은 작업을했지만 한 단계 더 나아갔습니다. 당신은 단어의 빈도를 보는 것을 좋아하지 않고 단어의 쌍과 삼중을 보는 것을 좋아 합니다. 예를 들어 "public"은 여러 언어에서 키워드 일 수 있지만 "public static void"는 C #에서 더 일반적입니다. 트리플을 찾을 수 없으면 2로 돌아가서 1로 돌아갑니다.
mpen

1
단어를 분할하는 위치에 대해 생각하고 싶을 수도 있습니다. PHP에서 변수는으로 시작 $하므로 는 변수와 함께 고정되어야 하므로 단어 경계로 분할 해서는 안됩니다$ . 같은 연산자 =>:=하나의 토큰으로 붙어 함께해야하지만, OTH 당신은 아마 해야 주위 분할 {그들은 항상 자신에 서 있기 때문들.
mpen 2010

2
네. 분할을 아예 피하는 방법은 ngram을 사용하는 것입니다. n 개 길이의 하위 문자열을 모두 가져옵니다. 예를 들어 "puts foo"의 5 그램은 "puts" "uts f", "ts fo"및 "s foo"입니다. 이 전략은 이상해 보일 수 있지만 생각보다 더 잘 작동합니다. 인간이 문제를 해결하는 방법이 아닙니다. 어떤 방법이 더 잘 작동하는지 결정하려면 둘 다 테스트해야합니다.
Jules

2
하지만 일부 언어에는 구문이 거의 없습니다. 나는 또한 공통 변수 이름이 언어의 키워드를 지배 할 것이라고 추측하고 있습니다. 기본적으로, 학습 데이터에 헝가리어로 작성된 변수 이름과 주석이 포함 된 C 코드가있는 경우 헝가리어가 포함 된 다른 소스는 "유사한"것으로 판단 될 수 있습니다.
tripleee 2011 년

26

다른 사람이 해결 한 언어 감지 :

Ohloh의 접근 방식 : https://github.com/blackducksw/ohcount/

Github의 접근 방식 : https://github.com/github/linguist


4
나는이 두 가지 해결책을 모두 검토했지만 어느 쪽도 요청 된대로 정확히 수행하지 않을 것입니다. 그들은 주로 언어를 결정하기 위해 파일 확장자를 확인하므로 확장자의 단서 없이는 스 니펫을 반드시 검사 할 수는 없습니다.
Hawkee

5
Github의 접근 방식에는 이제 베이지안 분류기도 포함됩니다. 주로 파일 확장자를 기반으로 언어 후보를 감지하지만 파일 확장자가 여러 후보 (예 : ".h"-> C, C ++, ObjC)와 일치하면 입력 코드 샘플을 토큰 화하고 사전 훈련 된 세트에 대해 분류합니다. 데이터 Github 버전은 확장 프로그램을 보지 않고도 항상 코드를 스캔하도록 할 수 있습니다.
Benzi



5

매우 어렵고 때로는 불가능합니다. 이 짧은 스 니펫은 어떤 언어에서 왔습니까?

int i = 5;
int k = 0;
for (int j = 100 ; j > i ; i++) {
    j = j + 1000 / i;
    k = k + i * j;
}

(힌트 : 여러 개 중 하나 일 수 있습니다.)

다양한 언어 분석을 시도하고 키워드의 빈도 분석을 사용하여 결정을 시도 할 수 있습니다. 특정 키워드 세트가 텍스트에서 특정 빈도로 발생하면 언어가 Java 등일 가능성이 높습니다.하지만 예를 들어 C에서 같은 이름의 변수에 이름을 지정할 수 있으므로 완전히 어리석은 증거를 얻을 수는 없다고 생각합니다. Java에서 키워드로 사용하고 빈도 분석은 속일 것입니다.

복잡도를 한 단계 끌어 올리면 구조를 찾을 수 있으며, 특정 키워드가 항상 다른 키워드 뒤에 오면 더 많은 단서를 얻을 수 있습니다. 그러나 설계하고 구현하는 것도 훨씬 더 어려울 것입니다.


26
여러 언어가 가능하다면 탐지기는 가능한 모든 후보를 제공 할 수 있습니다.
Steven Haryanto 2013 년

또는 일치하는 첫 번째 항목을 제공 할 수 있습니다. 실제 사용 사례가 구문 강조와 같은 경우에는 실제로 차이가 없습니다. 일치하는 언어가 있으면 코드가 올바르게 강조 표시됩니다.
jonschlinkert 19

5

대안은 사용하는 것입니다 highlight.js 수행 구문 강조하지만, 언어를 식별하기 위해 강조 프로세스의 성공 속도를 사용합니다. 원칙적으로 모든 구문 하이 라이터 코드베이스는 동일한 방식으로 사용될 수 있지만 highlight.js의 좋은 점은 언어 감지가 기능으로 간주되고 테스트 목적으로 사용 된다는 것입니다. 입니다.

업데이트 : 나는 이것을 시도했지만 잘 작동하지 않았습니다. 압축 된 JavaScript는 완전히 혼란 스러웠습니다. 즉 토크 나이 저는 공백에 민감합니다. 일반적으로 하이라이트 히트 수를 계산하는 것은 그다지 신뢰할 수없는 것 같습니다. 더 강력한 구문 분석기 또는 일치하지 않는 섹션 수가 더 잘 작동 할 수 있습니다.


highlight.js에 포함 된 언어 데이터는 강조 표시에 필요한 값으로 제한되며, 이는 언어 감지 (특히 소량의 코드)에 매우 불충분 한 것으로 나타났습니다.
아담 케네디

나는이 바이올린 함께 잘 체크 생각 jsfiddle.net/3tgjnz10
sebilasse

4

먼저, 특정 언어의 핵심 작업을 찾으려고합니다.

"package, class, implements "=> JAVA
"<?php " => PHP
"include main fopen strcmp stdout "=>C
"cout"=> C++
etc...

3
문제는 이러한 키워드가 변수 이름이나 문자열로 모든 언어로 여전히 나타날 수 있다는 것입니다. 그리고 사용 된 키워드가 많이 겹칩니다. 키워드를 보는 것 이상을해야합니다.
mpen 2010

2

가지고있는 스 니펫 유형에 따라 다르지만 일련의 토크 나이저를 통해 실행하고 어떤 언어의 BNF에 대해 유효한 것으로 나타 났는지 확인합니다.


모든 언어를 BNF로 설명 할 수도 없습니다. 키워드를 재정의하고 매크로를 만들 수 있다면 훨씬 더 어려워집니다. Alså는 스 니펫에 대해 이야기하고 있으므로 BNF에 대해 부분 일치를 수행해야하므로 더 어렵고 오류가 발생하기 쉽습니다.

2

멋진 퍼즐.

모든 언어를 감지하는 것은 불가능하다고 생각합니다. 그러나 키 토큰에서 트리거 할 수 있습니다. (특정 예약어 및 자주 사용되는 문자 조합).

유사한 구문을 가진 많은 언어가 있습니다. 따라서 스 니펫의 크기에 따라 다릅니다.


1

Prettify는 프로그래밍 언어를 감지하는 데 적합한 Javascript 패키지입니다.

http://code.google.com/p/google-code-prettify/

주로 구문 하이 라이터이지만 스 니펫에서 언어를 감지하기 위해 감지 부분을 추출하는 방법이있을 수 있습니다.


1
추가 검사에서 prettify는 실제로 언어를 감지하지 않는 것처럼 보이지만 각 요소의 구문에 따라 강조 표시됩니다.
Hawkee


1

나는 이것을 필요로 했으므로 내 자신을 만들었습니다. https://github.com/bertyhell/CodeClassifier

올바른 폴더에 교육 파일을 추가하여 매우 쉽게 확장 할 수 있습니다. C #으로 작성되었습니다. 그러나 코드가 다른 언어로 쉽게 변환 될 것이라고 생각합니다.


0

나는 이것을 달성하는 쉬운 방법이 없을 것이라고 생각합니다. 특정 언어 / 언어 클래스에 고유 한 기호 / 공통 키워드 목록을 생성 할 수 있습니다 (예 : C 스타일 언어의 경우 중괄호, BASIC 언어의 경우 Dim 및 Sub 키워드, Python의 경우 def 키워드, 기능적 언어의 경우 let 키워드). . 그런 다음 기본 구문 기능을 사용하여 범위를 더 좁힐 수 있습니다.


0

언어의 가장 큰 차이점은 구조라고 생각합니다. 그래서 제 생각은 모든 언어에서 공통적 인 요소를 살펴보고 어떻게 다른지 보는 것입니다. 예를 들어 정규식을 사용하여 다음과 같은 항목을 선택할 수 있습니다.

  • 기능 정의
  • 변수 선언
  • 클래스 선언
  • 코멘트
  • for 루프
  • while 루프
  • 명세서 인쇄

그리고 아마도 대부분의 언어가 가져야 할 몇 가지 다른 것들이 있습니다. 그런 다음 포인트 시스템을 사용하십시오. 정규식이 발견되면 각 요소에 대해 최대 1 점을 부여합니다. 분명히 일부 언어는 똑같은 구문을 사용합니다 (for 루프는 종종 다음과 같이 작성됩니다.for(int i=0; i<x; ++i) 여러 언어가 대해 점수를 매길 수 있도록 되지만 적어도 완전히 다른 언어가 될 가능성을 줄입니다). 그들 중 일부는 전반적으로 0 점을 기록 할 수 있지만 (예를 들어 스 니펫에는 함수가 전혀 포함되어 있지 않음) 완벽하게 괜찮습니다.

이것을 Jules의 솔루션과 결합하면 꽤 잘 작동합니다. 추가 요점을 위해 키워드 빈도를 찾을 수도 있습니다.


0

흥미 롭군. 다른 형식의 텍스트를 인식하는 비슷한 작업이 있습니다. YAML, JSON, XML 또는 Java 속성? 예를 들어 구문 오류가 있어도 JSON과 XML을 확실하게 구분해야합니다.

문제를 모델링하는 방법이 중요하다고 생각합니다. Mark가 말했듯이 단일 단어 토큰 화가 필요하지만 충분하지 않을 수 있습니다. 우리는 bigrams 또는 심지어 trigrams가 필요할 것입니다. 그러나 나는 우리가 프로그래밍 언어를 찾고 있다는 것을 알면 거기에서 더 멀리 갈 수 있다고 생각합니다. 거의 모든 프로그래밍 언어에는 기호키워드 라는 두 가지 고유 한 유형의 토큰이 있습니다. 기호는 비교적 쉽게 인식 할 수 있습니다 (일부 기호는 언어의 일부가 아닌 리터럴 일 수 있음). 그런 다음 기호의 바이그램 또는 트리 그램은 기호 주변의 고유 한 구문 구조를 선택합니다. 훈련 세트가 충분히 크고 다양한 경우 키워드는 또 다른 쉬운 목표입니다. 유용한 기능은 가능한 키워드에 대한 bigrams 일 수 있습니다. 또 다른 흥미로운 유형의 토큰은 공백입니다.. 실제로 일반적인 방식으로 공백으로 토큰 화하면이 정보가 손실됩니다. 프로그래밍 언어를 분석하기 위해 구문 구조에 대한 유용한 정보를 전달할 수 있으므로 공백 토큰을 유지합니다.

마지막으로 랜덤 포레스트와 같은 분류자를 선택하면 github를 크롤링하고 모든 공개 소스 코드를 수집합니다. 대부분의 소스 코드 파일은 파일 접미사로 레이블을 지정할 수 있습니다. 각 파일에 대해 빈 줄에서 무작위로 다양한 크기의 조각으로 분할합니다. 그런 다음 특성을 추출하고 레이블이 지정된 스 니펫을 사용하여 분류기를 훈련합니다. 훈련이 완료되면 분류기의 정밀도와 재현율을 테스트 할 수 있습니다.


0

내가 만난 최고의 솔루션 은 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애플리케이션의 디렉토리에서 실행할 수 있습니다 .

특히 레일이 아직없는 경우에는 많은 추가 작업처럼 보이지만,이 단계를 따르면 레일에 대해 실제로 알 필요가 없습니다. 그리고 저는 실제로 레일을 감지하는 더 좋은 방법을 찾지 못했습니다. 파일 / 코드 조각의 언어.


0

나는 단지 하나의 스 니펫을 기반으로 스 니펫이 어떤 언어로되어 있는지 식별 할 수있는 단일 솔루션이 없다고 생각합니다. 키워드를 사용하십시오 print. 여러 언어로 표시 될 수 있으며 각 언어는 용도가 다르고 구문도 다릅니다.

조언이 있습니다. 저는 현재 프로그래밍 언어를 식별하는 데 사용할 수있는 웹 사이트 용 코드를 작성하고 있습니다. 대부분의 다른 게시물과 마찬가지로 , 여러분이 듣지 못했던 프로그래밍 언어가 엄청나게 많을 수 있습니다 . 모두를 설명 할 수는 없습니다.

내가 한 것은 각 언어가 키워드 선택으로 식별 될 수 있다는 것입니다. 예를 들어, Python은 여러 가지 방법으로 식별 할 수 있습니다. 확실히 언어 고유의 '특성'을 선택하면 더 쉬울 것입니다. 파이썬의 경우 콜론을 사용하여 일련의 문을 시작하는 특성을 선택합니다. 이것은 상당히 독특한 특성이라고 생각합니다 (내가 틀렸다면 수정).

내 예에서 명령문 집합을 시작하는 콜론을 찾을 수없는 경우 가능한 다른 특성으로 이동 def합니다. 키워드를 사용하여 함수를 정의 한다고 가정 해 보겠습니다 . 이제 Ruby가 키워드 def를 사용하여 함수를 정의 하기 때문에 문제가 발생할 수 있습니다 . 둘 (Python과 Ruby)을 구분하는 핵심은 다양한 수준의 필터링을 사용하여 최상의 일치를 얻는 것입니다. Ruby는 키워드 end를 사용하여 함수를 완료하는 반면 Python은 함수를 완료하는 데 아무 것도없고 들여 쓰기 만 취소하지만 거기에 가고 싶지 않습니다. 그러나 다시 말하지만, endLua가 될 수도 있습니다. 또 다른 프로그래밍 언어가 추가 될 수 있습니다.

프로그래밍 언어가 너무 많이 오버레이된다는 것을 알 수 있습니다. 한 언어의 키워드가 될 수있는 하나의 키워드가 다른 언어의 키워드 일 수 있습니다. Java와 같이 자주 함께 사용되는 키워드 조합을 사용 public static void main(String[] args)하면 이러한 문제를 제거하는 데 도움이됩니다.

이미 말했듯이 가장 좋은 기회는 상대적으로 고유 한 키워드 또는 키워드 집합을 찾아서 서로 구분하는 것입니다. 그리고 만약 당신이 틀렸다면, 적어도 당신은 시도했습니다.


0

무작위 스크램블러를 다음과 같이 설정하십시오.

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;

0

이 사이트는 프로그래밍 방식으로 수행하는 대신 웹 양식에 스 니펫을 빠르게 붙여 넣는 방법을 원할 경우 언어 식별에 매우 능숙한 것 같습니다. http://dpaste.com/

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.