Ruby 프로그래밍 4 자료구조 응용 한국어 정보의 전산 처리 2017. 5. 8.
합격자 명단 파일에서 읽어오기 2 if ARGV.length < 2 print "이름이 명단에 있는지 검사. 명단파일, 이름을 입력" exit end names = File.open(ARGV[0], "r:UTF-8").readlines.map{ |s| s.chomp } #File objet의 메소드 readlines를 이용하여 각 라인들의 Array 만듦 #이 Array에 들어 있는 라인들은 줄바꿈 문자가 끝에 달려 있음 #map 메소드로 각 요소에 chomp 적용하여 줄바꿈 문자 떼어냄 print ( names.include? ARGV[1] ) ? "Yes" : "No"
표준국어대사전에서 주표제어, 부표제어 추출 File.open(ARGV[0], "r:UTF-8").each do |line| fs = line.chomp.split("#") mainlemma = fs[2][1..-1] #주표제어: 셋째 필드의 둘째 문자부터 끝 문자까지 sublemmas = fs.select{ |s| s.start_with?("6") }.map{ |s| s[1..-1] } #부표제어: 6으로 시작되는 필드들. 둘째 문자부터 끝 문자까지 print mainlemma, ",", sublemmas.join(","), "\n" end
품사별 빈도 통계: 형태소 분석 말뭉치 data = Hash.new # {pos => { form => freq } } File.open(ARGV[0], "r:UTF-8").each do |line| line.chomp.split(" ").each do |word| #라인을 어절별로 분리 word.split("+").each do |morph| #어절을 형태별로 분리 temp = morph.split("/") #형태를 /로 분리 case temp.size #/로 분리한 결과가 몇 개인가에 따라 별도 처리 when 2 #분리 결과가 2개. 즉 /가 1개인 경우. 정상적인 경우 form = temp[0] #/ 앞의 것은 form pos = temp[1] #/ 뒤의 것은 품사 when 3 # 분리 결과가 3개. 즉 /가 2개인 경우. 예: //SP form = "/" #/ 앞의 것은 "/" pos = temp[-1] # temp Array의 마지막 요소. ==temp[2] else # 분리 결과가 2개도 아니고 3개도 아닌 경우. 아마 없을 듯 print "Error: ", morph #에러 메시지 출력하고 exit #프로그램 종료 end
품사별 빈도 통계: 형태소 분석 말뭉치 data[pos] ||= Hash.new(0) #pos와 연결된 value가 이미 있으면(non-nil) 아무 일도 안 하고 #없으면(nil) Hash를 새로 만듦. default value 0 data[pos][form] += 1 #그 Hash에서 form과 연결된 value(즉 빈도)를 1 증가시킴 end data.each do |pos, dic| #data에 들어 있는 각 품사(pos) 및 이와 연결된 Hash(이름을 dic이라 함)에 대해 File.open(pos+".csv", "w:UTF-8") do |of| #pos.csv라는 쓰기용 파일을 엶 dic.sort{ |x,y| y[1]<=>x[1] }.each do |form, freq| #dic을 value(빈도) 내림차순으로 소팅하여 of << form << "," << freq << "\n" #form과 빈도를 출력
grep 흉내내기 사용자가 command line argument로 path, 정규표현 제시 파일이름, 라인번호, 그 라인에서 정규표현에 매치되는 부분의 시작, 끝 부분에 표시 넣어 출력하기 raise "사용법: ./grep_file.rb 파일이름 정규표현" if ARGV.size < 2 pattern = Regexp.new(ARGV[1]) File.open(ARGV[0], "r:UTF-8") do |f| # File object를 가리키는 변수를 f라 함 f.each do |line| line.chomp! if line =~ pattern #line이 정규표현 pattern에 매치되면 print f.lineno, ":", $`, "▶", $~.to_s, "◀", $', "\n“ #라인번호:매치앞부분▶매치부분◀매치뒤부분\n end
구성원-범주 → 범주-구성원 구조 변환 개화기 어휘에 대해 박사논문을 쓰고 있는 후배가 각 명사에 대해 의미부류/범주를 표시한 파일을 각 의미부류/범주에 속하는 명사들을 나열한 파일을 만들어 달라고 함. data = Hash.new #입력 파일을 분석하여 저장할 data strcuture. 결과물의 구조에 따라 만듦. # { 범주 => [단어,단어,단어,......] } File.open(ARGV[0], "r:UTF-8").each do |line| word, cats = line.chomp.split("\t") #탭으로 분리. 앞은 단어, 뒤는 범주목록 cats.split(/, ?/).each do |cat| #범주목록을 쉼표(+공백)로 분리 data[cat] ||= Array.new #cat이라는 key와 연결된 value(단어들의 Array)가 아직 없으면 만듦 data[cat] << word #이 Array에 word 추가 end data.sort.each do |cat, words| print cat, "\t", words.length, "\t", words.join(", "), "\n" # 범주, 탭, 단어개수, 탭, 단어목록
목록 비교: 차집합, 교집합, 합집합 require 'set' set1 = File.open(ARGV[0], "r:UTF-8").readlines.map{ |s| s.chomp }.to_set set2 = File.open(ARGV[1], "r:UTF-8").readlines.map{ |s| s.chomp }.to_set # 입력파일의 라인들을 Array로 읽어들여, 줄바꿈 떼어내고, set으로 변환 diff1 = set1 - set2 # set1.difference(set2)와 동일 diff2 = set2 - set1 # set2.difference(set1)과 동일 uni = set1 + set2 # set1.union(set2), set1|set2와 동일 inter = set1 & set2 # set1.intersection(set2)와 동일 print ARGV[0], " - ", ARGV[1], "\n" diff1.each{ |e| puts e } print ARGV[1], " - ", ARGV[0], "\n" diff2.each{ |e| puts e } print ARGV[0], " ∪ ", ARGV[1], "\n" uni.each{ |e| puts e } print ARGV[0], " ∩ ", ARGV[1], "\n" inter.each{ |e| puts e }
문자의 종류 알려주기 ARGV[0].each_char do |char| #문자열 ARGV[0]의 각 문자에 대해 print char, ": " puts case char.ord #ord 메소드: 문자 char의 코드값을 반환 when (0x0030..0x0039) then "숫자“ #then 대신에 줄바꿈도 가능 when (0x0041..0x005a) then "로마자 대문자" when (0x0061..0x007a) then "로마자 소문자" when (0xac00..0xd7a3) then "한글" when (0x3400..0x4db5), (0x4e00..0x9fa5), (0xf900..0xfa6a) then "한자“ # when 뒤에 여러 값/range를 쉼표로 나열할 수 있음 else “기타“ #위의 when에 나열된 경우들에 걸리지 않은 나머지 경우 end #case ~ when ~ else ~ end 블록의 끝. #char.ord가 속하는 범위(when 뒤의 range)에 해당하는 then 뒤의 값 반환 end