2017-04-08 6 views
2

Flexlm/Flexnet 라이센스 서비스를 보유하고 있으며이 서비스의 출력을 분석하고 싶습니다. 모든 출력은 멀티 라인의 구조화 된 블록입니다. 내 첫 번째 단계는 lmutil lmstat -c <[email protected]> -a의 출력을 구문 분석하여 라이센스 및 증분을 사용하는 것입니다.Ruby & Lmstat : parslet 및 구조화 된 멀티 라인 블록 : 어디에서 개행 명령문을 넣을까요?

Ruby와 Parslet을 사용하려고합니다. 모든 라인은 개별적으로 잘 분석됩니다. 특정 유형의 라인 반복을 구문 분석하는 규칙이 있지만 구조화 된 블록 블록을 구문 분석 할 수 없습니다.

저는 '줄 바꿈'구문을 여러 줄짜리 구조화 된 블록에 넣을 위치를 정의하는 법칙 ('규칙'보다이 문맥에서 가장 좋은 단어)을 찾고 있습니다.

저는 Debian Jessie (stable/x86_64)와 Ruby 2.1.5p273 및 Parslet 1.6.1-1로 작업했습니다.

나는 저자에게 연락했으나 미안하지만 그는 나를 도울 시간이 부족합니다. 본 웹 페이지는 다음과 같습니다

  • URL : www.viget.com/articles/write-you-a-parser-for-fun-and-win
  • URL : jmettraux.wordpress.com/2011/05/11/parslet 앤 JSON/
  • 재귀 하강 파서 (칼레) - 비디오
  • Wicked Good Ruby 2013 - Writing DSL's with Parslet by Jason Garber - Video
  • 여러 줄 방법 ​​체인 포함 된 블록에 대한 적절한 루비 스타일 - 유래
  • 루비 parslet : 여러 줄을 구문 분석 - StackOverFlow
  • Parslet을 사용하여 Ruby에서 C 스타일 주석을 처리하는 방법은 무엇입니까? - StackOverFlow

여러 줄로 구성된 구조적 블록의 규칙을 구성하는 방법을 이해하려고 많은 시간을 보냈습니다. 아래에는 모든 테스트 문자열과 출력이 포함 된 소스 코드가 있습니다.

내 접근 방식은 구축하는 것입니다 :

  1. 초등학교 규칙을 라인의 조각을 구문 분석
  2. '줄 바꿈'문없이 전체 라인을 구문 분석하는 규칙;
  3. 사용 된 토큰에 대한 행과 같이 동일한 유형의 정보의 반복을 구문 분석하는 규칙.
  4. 데이터 그룹을 구문 분석하는 규칙입니다. header + lines of repetitions;
  5. 그룹의 반복을 구문 분석하는 규칙입니다.

3 점이 확실하지 않으며 '4'와 '5'로 완전히 잃어 버렸습니다.

미리 도움을 청하십시오.

[UPDATE - 2017년 4월 29일 :

#!/usr/bin/env ruby 
# This code try to parse the output of 'lmutil lmstat -c <[email protected]> -a'. 
require 'parslet' 
require 'parslet/convenience' 
require 'pp' 

### Begin of the class Lmstat 
class Lmstat < Parslet::Parser 

### 
# Small parts to parse 
rule(:digit)  { match(/\d/).repeat(1) } 
rule(:space)  { str(' ').repeat } 
rule(:eof)   { any.absent? } 
rule(:blank_line) { space.maybe >> newline >> space.maybe } 
rule(:newline)  { str("\r").maybe >> str("\n") } 
rule(:txt)   { match(/[\w\d\s,_.'",-:]/).repeat } 

def parenthese(atom, qte='()') 
    if (qte == '()') 
    str('(') >> atom >> str(')') 
    else 
    str(qte) >> atom >> str(qte) 
    end 
end 
### 


### 
# The header is not parsed for the moment, while I can't 
rule (:header) do 
    # Not define until the other parts are OK. 
end 


rule(:feature_line) do 
    feature_usage.as(:feature_line) >> # newline >> 
    feature_line_id.as(:feature_line_id).repeat.as(:f_line) 
end 

rule(:feature_line_id) do 
    feature_version >> newline >> feature_type >> newline >> 
    feature_user_group >> newline 
end 

rule(:feature_line_id_group) do 
    (newline >> feature_line_id).repeat(1).as(:f_line_group) >> newline 
end 


rule(:feature_usage) do 
    str("Users of ") >> feature.as(:feature_usage) >> str(':') >> space >> 
    parenthese(feature_used) >> space.maybe 
end 

rule(:feature) { match(/[\w_-]/).repeat } 

# Total of 1 license issued; Total of 0 licenses in use 
rule(:feature_used) do 
    feature_token.as(:feature_token_issued) >> 
    feature_token.as(:feature_token_used) >> space.maybe >> newline.maybe 
end 

# (Total of 1 license issued; Total of 0 licenses in use) 
rule(:feature_token) do 
    space.maybe >> str('Total of ') >> digit.repeat.as(:feature_token_value) >> 
    space >> license >> issued_used >> 
    str(';').maybe >> space.maybe 
end 

rule(:license) { str('license') >> str('s').maybe >> space } 

rule(:issued_used) do 
    str('issued') | str('in use') 
end 

# v2015.1231 
rule(:version) { match(/[\w\d.-]/).repeat } 

# "incr-1" 
rule(:vendor) { match(/[\w-]/).repeat } 

# "incr-1" v2015.1231, vendor: ansoftd 
rule(:feature_version) do 
    # newline >> 
    space.maybe >> parenthese(feature.as(:feature), '"') >> 
    space >> version.as(:version) >> str(', vendor: ') >> 
    vendor.as(:vendor) >> space.maybe >> 
    str(', expiry: ').maybe >> match(/[\w\d-]/).repeat.as(:expiration).maybe 
end 

# floating license 
# nodelocked license, locked to "ID=12345" 
rule(:feature_type) do 
    space.maybe >> 
    ((space.maybe >> str("floating license").as(:floating) >> space.maybe) | 
     (space.maybe >> str('nodelocked license, locked to "ID=') >> 
     digit.as(:license_id) >> str('"') >> space.maybe)).as(:feature_type) >> 
    space.maybe 
end 

# \t 28 RESERVATIONs for GROUP Better_Group (server/27000) 
rule(:reserve) do 
    space.maybe >> str("\t").maybe >> digit.as(:reserve_value) >> 
    str(" RESERVATION") >> str("s").maybe >> str(" for ") >> 
    word.as(:reserve_type) >> space >> word.as(:reserve_who) >> 
    space >> 
    parenthese(host.as(:server) >> str("/") >> digit.as(:port)) 
end 

rule(:reserve_group) do 
    (newline >> reserve).repeat(1).as(:reservation) 
end 

rule(:feature_user) do 
    space.maybe >> 
    word.as(:login) >> space >> host.as(:host_user) >> space >> host.as(:id) >> 
    space >> parenthese(version.as(:version)) >> space >> port >> date_queue 
end 

rule(:feature_user_group) do 
    (newline >> feature_user).repeat(1).as(:feature_user_group) 
end 

# queued for 1 license 
rule(:queue) do 
    str('queued for ') >> digit.as(:queued) >> str(' license') >> str('s').maybe 
end 

rule(:date_queue) do 
    ((str(',') >> space >> date >> cmt.as(:comment)) | (space >> queue)) 
end 

rule(:cmt) do 
    space.maybe >> match(/[^\r\n]/).repeat#.as(:cmt) 
end 

rule(:word) { match(/[\w\d-]/).repeat } 
rule(:host) { match(/[\w\d_.-]/).repeat } 

rule(:port) do 
    parenthese(host.as(:server) >> str('/') >> digit.as(:server_port) >> 
       space >> digit.as(:vendor_port)) 
end 

rule(:date) do 
    str('start ') >> word.as(:date_dayname) >> space >> 
    digit.as(:date_month) >> str('/') >> digit.as(:date_day) >> space >> 
    digit.as(:date_hour) >> str(':') >> digit.as(:date_minute) 
end 

end 
### End of the class Lmstat 

### 
# Some multiline tests case. 

t_feature_line_id = %q{ "incr-2" v9999.9999, vendor: vendor-daemon 
    floating license 

    henry abc057 abc057 (v2015.0623) (shoe/28512 3886) queued for 1 license 
    simon abc057 abc057 (v2014.1110) (shoe/28512 4166), start Fri 11/20 15:37, 10 licenses 
    simon abc057 abc057 (v2014.1110) (shoe/28512 4166), start Fri 11/20 15:37 queued for 1 license 
} 


t_feature_line_id_group = %q{ "incr-2" v9999.9999, vendor: vendor-daemon 
    floating license 

    henry abc057 abc057 (v2015.0623) (shoe/28512 3886) queued for 1 license 
    jason abc057 abc057 (v2015.0623) (shoe/28512 3886), start Fri 11/20 14:41 
    simon abc057 abc057 (v2014.1110) (shoe/28512 4166), start Fri 11/20 15:37, 10 licenses 
    simon abc057 abc057 (v2014.1110) (shoe/28512 4166), start Fri 11/20 15:37 queued for 1 license 

    "inc2" v9999.9999, vendor: inc2vendor 
    floating license 

    simon abc057 abc057 (v2014.1110) (shoe/28512 4166), start Fri 11/20 15:37, 10 licenses 
    simon abc057 abc057 (v2014.1110) (shoe/28512 4166), start Fri 11/20 15:37 queued for 1 license } 


t_feature_line = %q{Users of ansys: (Total of 9 licenses issued; Total of 6 licenses in use) 

    "incr-2" v9999.9999, vendor: vendor-daemon 
    floating license 

    jason abc057 abc057 (v2015.0623) (shoe/28512 3886), start Fri 11/20 14:41 
    simon abc057 abc057 (v2014.1110) (shoe/28512 4166), start Fri 11/20 15:37, 10 licenses 
    simon abc057 abc057 (v2014.1110) (shoe/28512 4166), start Fri 11/20 15:3} 

t_feature_line_group = %q{ 
    "incr-2" v9999.9999, vendor: vendor-daemon 
    floating license 

    jason abc057 abc057 (v2015.0623) (shoe/28512 3886), start Fri 11/20 14:41 
    simon abc057 abc057 (v2014.1110) (shoe/28512 4166), start Fri 11/20 15:37, 10 licenses 
    simon abc057 abc057 (v2014.1110) (shoe/28512 4166), start Fri 11/20 15:37 queued for 1 license 

    "incr-2" v9999.9999, vendor: vendor-daemon 
    floating license 

    jason abc057 abc057 (v2015.0623) (shoe/28512 3886), start Fri 11/20 14:41 
    simon abc057 abc057 (v2014.1110) (shoe/28512 4166), start Fri 11/20 15:37, 10 licenses 
    simon abc057 abc057 (v2014.1110) (shoe/28512 4166), start Fri 11/20 15:37} 

t_feature_user= %q{jason abc057 abc057 (v2015.0623) (shoe/28512 3886), start Fri 11/20 14:41} 

t_feature_group = %q{ "incr-2" v9999.9999, vendor: vendor-daemon 
    floating license 

    jason abc057 abc057 (v2015.0623) (shoe/28512 3886), start Fri 11/20 14:41 
    simon abc057 abc057 (v2014.1110) (shoe/28512 4166), start Fri 11/20 15:37, 10 licenses 
    jessica abc057 abc057 (v2014.1110) (shoe/28512 4166), start Fri 11/20 15:37 

    "MATLAB" v35, vendor: MLM, expiry: 01-jan-0000 
    nodelocked license, locked to "ID=12345" 

    albert node7563 node7563 (v34) (shoe/27000 201), start Mon 5/23 6:16 (linger: 1235700) 
    victoria abc087 /dev/pts/1 (v29) (shoe/27000 3401), start Mon 5/23 6:30} 
### 

### 
# Method to test the parsing. 
def parse_method(method,str) 
    lmstat = Lmstat.new 
    unless lmstat.respond_to?(method) 
    raise ArgumentError, 
      "\n\n\t***** ERROR: Unknown method -> '#{method}' ******\n\n", 
      caller[1..-1] 
    end 
    begin 
    m = "lmstat.#{method}.parse('"+ str + '\')' 
    puts "=> Test of #{m}" 
    eval (m) 
    rescue Parslet::ParseFailed => failure 
    puts failure.cause.ascii_tree 
    end 
end 
### 

### 
# Not called if 'irb' is used to load the program. 
if __FILE__ == $PROGRAM_NAME 
    puts "\n ###### Multilines #####" 
     parse_method('feature_user_group',t_feature_user_group) 
     parse_method("feature_line_id",t_feature_line_id) 
     pp parse_method("feature_line_id_group",t_feature_line_id_group) 
end 

출력 [기능 버전을 넣어 제거 2017년 7월 13일]를 [2017년 7월 14일 코드의 일부는 제거되었다] - Problem solved] Nigel Thorne에게 감사의 말을 전합니다. 문제가 해결되었습니다.당신의 충고에 따라 '공간'에 대한 규칙을 수정했습니다.

[07/13/2014 : 일부 기능을 제거하려면 일부 텍스트를 삭제하십시오. ]

[UPDATE - 2017년 7월 13일 - 응용 프로그램을 테스트 할 수있는 분석]

나는 루비와 Parslet와 lmstat의 출력의 구문 분석을 테스트 할 수있는 응용 프로그램을 완료했습니다. 구문 분석은 각 편집기에 따라 다르므로 일부 경우는 다룰 수 없지만 30 개 이상의 라이센스 서비스를 사용하여 구문 분석의 유효성을 검사합니다.

  1. parse_lmstat.rb : 도움을 가지고 사용 './parse_lmstat --help'

    나는 3 개 개의 파일을 줄 수 있습니다. 구문 분석을 테스트하는 응용 프로그램입니다.

  2. readstdin_lmstat.rb : YAML 형식으로 생성 된 구문 분석 된 lmstat의 출력을 STDIN에서 읽습니다.
  3. display_lmstat.rb : 데이터에서 액세스하는 방법을 보여 주며 구문 분석의 구조를 개선하는 데 사용되었습니다. 스크립트는 단순히 irb 세션보다 좋습니다. 그것은 STDIN에서 구문 분석 된 lmstat의 출력을 YAML 형식으로 읽습니다.

예 : 알려진

~/bin/lmutil lmstat -a -c [email protected] | ./parse_lmstat.rb --screen | ./display_lmstat.rb 

한 버그 : A [CTRL-C]이 신호 할 때 잘 갇혀되지 않는 것 같다 루비 경우에 일부 오류 메시지를 보냅니다.

이제 라이선스 서버를 선택하고 데이터를 표시 할 작은 WEB 응용 프로그램 (SINATRA?)을 갖고 싶지만 HTML 또는 CSS를 말할 수는 없습니다 ... 어떤 도움도 감사하겠습니다 ;-)

아래와 같이 은 30000 자로 제한되어 있으므로 클래스 만 구문 분석하고 lmstat의 출력을 변환 할 수 있습니다.

#!/usr/bin/env ruby 
# 
# class_lmstat.rb 
# 
# This code try to parse the output of 'lmutil lmstat -c <[email protected]> -a'. 
# 
# Scapin - 11/07/2017 
# 
# For the Stackoverflow forums 
# 
require 'parslet' 
require 'parslet/convenience' 
require 'open3' 

### Begin of the class Lmstat 
class Lmstat < Parslet::Parser 

### 
# Small parts to parse 
rule(:digit)  { match(/\d/).repeat(1) } 
rule(:space)  { str(' ').repeat(1) } 
rule(:eof)   { any.absent? } 
rule(:blank_line) { space.maybe >> newline >> space.maybe } 
rule(:newline)  { str("\r").maybe >> str("\n") } 
rule(:txt)   { match(/[\w_.\)\('\t ",-:\\]/).repeat } 
rule(:word)  { match(/[\w-]/).repeat } 
rule(:host)  { match(/[\w_\.-]/).repeat } 
rule(:cnx_id)  { match(/[\/\w_.:]/).repeat } 
rule(:cmt)   { space.maybe >> match(/[^\r\n]/).repeat } 
rule(:error_code) { match(/[,\d-]/).repeat } 

def parenthese(atom, qte='()') 
    if (qte == '()') 
    str('(') >> atom >> str(')') 
    else 
    str(qte) >> atom >> str(qte) 
    end 
end 
### 

root(:lmstat) 

rule(:lmstat) do 
    (header.as(:header) >> body.repeat.as(:service) >> newline).as(:lmstat) 
end 

### 
# The header is not parsed for the moment, while I can't 
# handle the multiline block correctly. 
# 
# lmutil - Copyright (c) 1989-2013 Flexera Software LLC. All Rights Reserved. 
# Flexible License Manager status on Fri 11/20/2015 16:39 
# 
# License server status: [email protected] 
#  License file(s) on lic-server: /opt/license/soft/vendor1.lic:/opt/license/soft/vendor2.lic: 
# 
#  lic-server: license server UP (MASTER) v11.13 
# 
# Vendor daemon status (on lic-server): 
# 
# vendor-daemon: UP v11.13 
# Feature usage info: 
# 
### 
rule (:header) do 
    copyright >> status_date >> newline >> 
    server >> license_file >> newline >> 
    server_status >> newline >> 
    vendor_daemon_status >> newline 
end 

rule (:body) do 
    (vendor_daemon.as(:vendor_daemon) >> feature_info.maybe >> newline >> 
    feature_line.repeat.maybe.as(:features)) 
end 

# lmutil - Copyright (c) 1989-2013 Flexera Software LLC. All Rights Reserved. 
rule (:copyright) do 
    space.maybe >> (str("lmutil - Copyright ") >> match(/./).repeat).as(:copyright) >> newline 
end 

# Flexible License Manager status on Fri 11/20/2015 16:39 
rule(:status_date) do 
    space.maybe >> str("Flexible License Manager status on ") >> 
    word.as(:status_dayname) >> space >> 
    digit.as(:status_month) >> str("/") >> digit.as(:status_day) >> 
    str("/") >> digit.as(:status_year) >> 
    str(" ") >> digit.as(:status_hour) >> 
    str(":") >> digit.as(:status_min) >> newline 
end 

rule(:server) do 
    str("License server status: ") >> 
    digit.as(:server_port1) >> str("@") >> host.as(:server1) >> 
    (str(",") >> digit.as(:server_port2) >> str("@") >> host.as(:server2) >> 
    str(",") >> digit.as(:server_port3) >> str("@") >> host.as(:server3)).maybe >> 
    newline 
end 

# License file(s) on lic-server: /opt/license/soft/licfile-1.lic:/opt/soft/licfile-2.lic: 
rule(:license_file) do 
    space.maybe >> str("License file(s) on ") >> 
    match(/[\w\d._-]/).repeat.as(:license_files_server) >> 
    str(": ") >> txt.as(:license_files_names) >> newline 
end 

rule(:server_status) do 
    (space.maybe >> host.as(:server_host) >> str(": ") >> 
    (server_up | server_down) >> newline).repeat(0).as(:server_list) 
end 

rule(:server_up) do 
    str("license server ")>>str("UP").as(:server_up)>> 
    server_pos.maybe >> str(" ") >> cmt.as(:server_version) 
end 

rule(:server_pos) do 
    space >> parenthese(match(/[A-Za-z]/).repeat.as(:server_role)) 
end 


# licserver: Cannot connect to license server system. (-15,570:115 "Operation now in progress") 
rule(:server_down) do 
    space.maybe >> str("Cannot connect to license server system").as(:server_down) >> 
    str(". ") >> cmt.as(:server_error) 
end 

rule(:vendor_daemon_status) do 
    str("Vendor daemon status (on ") >> host.as(:server_daemon) >> 
    str("):") >> space.maybe >> newline 
end 

rule(:vendor_daemon) do 
    (vendor_daemon_up | vendor_daemon_down) 
end 

rule(:vendor_daemon_up) do 
    space.maybe >> word.as(:daemon) >> str(": ") >> word.as(:daemon_status) >> 
    space >> host.as(:daemon_version) >> newline 
end 

rule(:vendor_daemon_down_ini) do 
    space.maybe >> word.as(:daemon) >> str(": The desired vendor daemon is down. ") >> 
    parenthese(error_code.as(:daemon_status)) >> space.maybe >> newline 
end 

# \n\n dconcept: No socket connection to license server manager. (-7,96) 
rule(:vendor_daemon_down) do 
    space.maybe >> word.as(:daemon) >> str(": The desired vendor daemon is down. ") >> 
    parenthese(error_code.as(:daemon_status)) >> space.maybe >> newline 
    space.maybe >> word.as(:vendor_daemon_down_msg_feature).maybe >> 
    str(': No socket connection to license server manager.').maybe >> space.maybe >> 
    cmt.as(:vendor_daemon_down_msg).maybe >> newline.maybe 
end 

rule(:feature_info) do 
    space.maybe >> str("Feature usage info:") >> space.maybe >> newline 
end 


### 
# Users of soft_a: (Total of 1 license issued; Total of 0 licenses in use) 
# 
# "incr-1" v2015.1231, vendor: soft_ad 
# floating license 
# 
# 28 RESERVATIONs for GROUP Better_Group (server/27000) 
# 1 RESERVATION for USER toni (server/27000) 
# scott abc056 abc056 (v2015.0623) (shoe/28512 3644), start Fri 11/20 15:45, 2 licenses 
# scott abc056 abc056 (v2015.0623) (shoe/28512 4669), start Fri 11/20 15:45, 10 licenses 
rule(:feature_line) do 
    feature_usage.as(:feature_line) >> newline >> 
    feature_line_id.repeat(0).as(:feature_line_id) 
end 

# "incr-1" v2015.1231, vendor: soft_ad 
# floating license 
# 
# scott abc056 abc056 (v2015.0623) (shoe/28512 3644), start Fri 11/20 15:45, 2 licenses 
# scott abc056 abc056 (v2015.0623) (shoe/28512 4669), start Fri 11/20 15:45, 10 licenses 
rule(:feature_line_id) do 
    feature_version >> newline >> feature_type >> newline >> 
    # (reserve.as(:reservation) | feature_user.as(:user)).repeat(1).as(:users) >> newline 
    (reserve.as(:reservation) | feature_user.as(:user)).repeat(1).as(:who) >> newline 
end 

# Users of soft_a: (Total of 1 license issued; Total of 0 licenses in use) 
# Users of SOFT_B: (Uncounted, node-locked) 
# Users of soft_c: (Error: 6 licenses, unsupported by licensed server) 
rule(:feature_usage) do 
    str("Users of ") >> feature.as(:feature_name) >> str(':') >> space >> 
    parenthese(feature_used) >> space.maybe >> newline 
end 


# Total of 1 license issued; Total of 0 licenses in use 
# Uncounted, node-locked 
rule(:feature_used) do 
    ((feature_token.as(:feature_token_issued) >> feature_token.as(:feature_token_used)) | 
    (word.as(:feature_token_issued) >> str(', ') >> word.as(:feature_token_used)) | 
    (str('Error: ') >> digit.repeat.as(:feature_token_error) >> space >> str('license') >> 
     str('s').maybe >> str(', ') >> 
     match(/[\w_', :-]/).repeat.as(:feature_token_error_cause))) >> 
    space.maybe >> newline.maybe 
end 

# (Total of 1 license issued; Total of 0 licenses in use) 
rule(:feature_token) do 
    space.maybe >> str('Total of ') >> digit.repeat.as(:feature_token_value) >> 
    space >> license >> issued_used >> 
    str(';').maybe >> space.maybe 
end 

rule(:license) { str('license') >> str('s').maybe >> space } 

rule(:issued_used) do 
    str('issued') | str('in use') 
end 

# v2015.1231 
rule(:version) { match(/[\w\d.-]/).repeat } 

# "incr-1" 
rule(:vendor) { match(/[\w-]/).repeat } 

rule(:feature) { match(/[\w\d\/_+-]/).repeat } 

# "incr-1" v2015.1231, vendor: soft_ad 
rule(:feature_version) do 
    # newline >> 
    space >> parenthese(feature.as(:feature), '"') >> 
    space >> version.as(:version) >> str(', vendor: ') >> 
    vendor.as(:vendor) >> space.maybe >> 
    str(', expiry: ').maybe >> match(/[\w\d-]/).repeat.as(:expiration).maybe 
end 

rule(:feature_type) do 
    space >> (float_type | node_type).as(:feature_type) 
end 

# floating license 
rule(:float_type) do 
    str("floating license").as(:floating) >> cmt.maybe >> newline 
end 

# nodelocked license, locked to "ID=654321" 
# nodelocked license locked to NOTHING (hostid=ANY) 
# uncounted nodelocked license locked to NOTHING (hostid=ANY) 
# uncounted nodelocked license, locked to Vendor-defined "PTC_HOSTID=01-0A-01-0A-01" 
rule(:node_type) do 
    str('uncounted ').maybe >> str("nodelocked license") >> str(',').maybe >> str(' locked to ').maybe >> 
    ((str('"ID=') >> digit.as(:nodelocked_id) >> str('"')) | 
    (host.as(:nodelocked_to) >> space >> parenthese(str('hostid=') >> host.as(:nodelocked_hostid))) | 
    (host.as(:nodelocked_to) >> space >> 
            parenthese(match(/[\w:_=' -]/).repeat.as(:nodelocked_hostid), '"'))) >> 
    space.maybe >> newline 
end 

# \t 28 RESERVATIONs for GROUP Better_Group (server/27000) 
rule(:reserve) do 
    space.maybe >> str("\t").maybe >> digit.as(:reserve_value) >> 
    str(" RESERVATION") >> str("s").maybe >> str(" for ") >> 
    word.as(:reserve_type) >> space >> word.as(:reserve_who) >> 
    space >> 
    parenthese(host.as(:server) >> str("/") >> digit.as(:port)) >> 
    newline 
end 

rule(:feature_user) do 
    (u_std | u_aselta | u_ans | u_c1 | u_c2) 
end 

# scott abc056 abc056 (v2015.0623) (shoe/28512 3644), start Fri 11/20 15:45, 2 licenses 
# albert node7563 node7563 (v34) (shoe/27000 201), start Mon 5/23 6:16 (linger: 1235700) 
# hector node088 dev/tty (v2015.0312) (licserver/1446 3730), start Thu 11/19 9:08 
# will pim.my.domain.org pim.my.domain.org 6656 (v2016.1129) (licserver/1446 2216), start Fri 5/12 14:51 
rule(:u_std) do 
    space >> word.as(:login) >> space >> host.as(:host_user) >> space >> 
    cnx_id.as(:host_id) >> 
    space >> parenthese(version.as(:version)) >> space >> port >> date_queue >> 
    newline 
end 

# scott cat :0 Token Lic (v7.000) (shoe/5300 15434), start Thu 7/6 17:07 
rule(:u_c1) do 
    space >> word.as(:login) >> space >> host.as(:host_user) >> space >> 
    cnx_id.as(:host_id) >> space >> match(/[^(]/).repeat.as(:common_name) >> 
    parenthese(version.as(:version)) >> space >> port >> date_queue >> 
    newline 
end 

# jessie cat bird:1144.0 APS Multi-core (Max. 16 cores) (v11.100) (licserver/5303 13188), start Thu 7/6 15:22, 4 licenses 
rule(:u_c2) do 
    space >> word.as(:login) >> space >> host.as(:host_user) >> space >> 
    cnx_id.as(:host_id) >> space >> match(/[^(]/).repeat.as(:common_name) >> 
    str('(') >> match(/[^)]/).repeat.as(:common_info) >> str(')') >> space >> 
    parenthese(version.as(:version)) >> space >> port >> date_queue >> 
    newline 
end 

# tiger pam.my.domain.org pam.my.domain.org 6656 (v2016.1129) (licserver/1446 2216), start Fri 5/12 14:51 
rule(:u_ans) do 
    space >> word.as(:login) >> space >> host.as(:host_user) >> space >> 
    cnx_id.as(:host_id) >> (space >> host.as(:further)).maybe >> 
    space >> parenthese(version.as(:version)) >> space >> port >> date_queue >> 
    newline 
end 


# clark node07 SOMETHING Inscale/grid (worker) (v1.0) (licserv01/27016 5506), start Fri 4/28 13:42, 4 licenses 
# bunny orca SOMETHING Inscale/graphical (v1.0) (licserv01/27016 650), start Thu 4/13 10:27 
rule(:u_aselta) do 
    space >> word.as(:login) >> space >> host.as(:host_user) >> space >> 
    word.as(:daemon) >> space >> word.as(:soft) >> str("/") >> 
    word.as(:function) >> (space >> parenthese(word.as(:tools))).maybe >> 
    space >> parenthese(version.as(:version)) >> space >> port >> date_queue >> 
    newline 
end 

# queued for 1 license 
rule(:queue) do 
    str('queued for ') >> digit.as(:queued) >> str(' license') >> str('s').maybe 
end 

rule(:lic) do 
    str(',') >> space >> digit.as(:licenses) >> str(' license') >> str('s').maybe 
end 

rule(:date_queue) do 
    ((str(',') >> space >> date >> (lic | cmt.as(:comment))) | (space >> queue)) 
end 

rule(:port) do 
    parenthese(host.as(:server) >> str('/') >> digit.as(:server_port) >> 
       space >> digit.as(:vendor_port)) 
end 

rule(:date) do 
    str('start ') >> word.as(:date_dayname) >> space >> 
    digit.as(:date_month) >> str('/') >> digit.as(:date_day) >> space >> 
    digit.as(:date_hour) >> str(':') >> digit.as(:date_minute) 
end 

end 
### End of the class Lmstat 


### Begin of the class Trans 
class Trans < Parslet::Transform 
    rule(:feature_token_value => simple(:v)) { Integer(v) } 

    rule(:user => subtree(:t)) do 
    if (t.has_key?(:date_month)) 
     cal = { "Sun"=>"Dimanche", "Mon"=>"Lundi", "Tue"=>"Mardi", 
       "Wed"=>"Mercredi", "Thu"=>"Jeudi", "Fri"=>"Vendredi"} 
     clock = Time.now 

     # Addition of keys 
     t.merge!({ :date_year => 0, :since => "", :delay_min => 0, :delay_string => ""}) 

     # Convert to integer 
     t[:date_minute] = t[:date_minute].to_s.sub(/^0/,"") if (t.has_key?(:date_minute)) 
     t.each do |k,v| 
     [ :server_port, :vendor_port, :date_month, :date_day, 
      :date_hour, :date_minute, :queued, :licenses ].each do |symbol| 
      t[k] = Integer(v) if k == symbol 
     end 
     end 

     t[:date_dayname] = cal[t[:date_dayname].to_s] 
     t[:date_year] = clock.year 
     t[:date_year] = t[:date_year] - 1 if (clock.month < t[:date_month]) 
     t[:since] = sprintf("%2.2d/%2.2d/%2d-%2.2d:%2.2d", t[:date_day], t[:date_month], 
          t[:date_year], t[:date_hour], t[:date_minute]) 
     t[:delay_min], t[:delay_string] = Tools.delay(clock, t[:date_year], 
       t[:date_month], t[:date_day], t[:date_hour], t[:date_minute], 0) 
     t[:delay_min] = Integer(t[:delay_min]/60) 
     t[:delay_string].chop!.chop!.chop! 

     # Add a key for a borrowed token. 
     t.merge!({:borrow => true}) if (/linger/ =~ t[:comment]) 
    end 

    # Restore the hash. 
    { :user => t } 
    end 

end 
### 


#### 
module Tools 

    def Tools.check_file(file) 
    return false unless file 
    if File.exist?(file) 
     File.file?(file) 
    else 
     false 
    end 
    end 


    def Tools.delay(clock = Time.now, year, month, day, hour, minute, second) 
    delay = clock - Time.local(year.to_i,month.to_i,day.to_i,hour.to_i,minute.to_i, second.to_i) 
    d = delay.divmod(3600.0*24.0) 
    h = d[1].divmod(3600.0) 
    m = h[1].divmod(3600.0)[1].divmod(60.0) 
    s = m[1].divmod(60.0)[1].divmod(60.0) 
    [ delay, sprintf("%3.3dj%2.2dh%2.2dmin%2.2ds", d[0], h[0], m[0], s[1].round) ] 
    end 


    def Tools.grab_list(list_file, separator = ' ') 
    return nil unless Tools.check_file(list_file) && File.stat(list_file).readable? 
    lines = Array.new 
    list = Array.new 
    open(list_file).each_line { |l| lines << l.chomp if l } 
    # 'split' ignore the multiple '/\s/'. 
    lines.each { |l| list.concat(l.split(separator)) } 
    # Suppress the spaces if the separator isn't a "\s". 
    list.each_index { |i| list[i]= list[i].delete(" ") } unless 
    list.delete_if { |l| l.length < 1 } 
    list 
    end 

    def Tools.create_output(name_of_file, extension = '', mode = "w") 
    begin 
     file_name = name_of_file + extension 
     line = __LINE__; File.new(file_name, mode) 
    rescue Errno::EACCES => error_create 
     STDERR.puts $PROGRAM_NAME + "(#{line})" + 
     " ERREUR ! create_output(\"#{file_name}\")" 
     STDERR.puts $PROGRAM_NAME + "(#{line})" + 
     " ERREUR ! Message = '#{error_create.message}'" 
     raise error_create 
    end 
    end 
end 
### 
+0

왜 모든 개행 문을 정리하여 통일되게 만드십니까 – Tsao

+0

Hello Tsao, 죄송합니다. 영어가 모국어가 아니므로, 무슨 뜻인지 이해가되지 않습니다. 당신의 발언을 발전시킬 수 있습니까? 감사. – Scapin

+0

새 질문을 열어야합니다 ...이 질문을 확장하지 마십시오. (또는 사람들은 질문에 대한 좋은 답변을 찾기 위해 사이트를 사용할 수 없습니다.) –

답변

1

"개행"문제가있는 것 같습니다.

좋은 지침은 ... * 규칙 끝에 (종료 문자로) 사용하십시오. * 기호가 토큰의 일부가 아닌 경우 부모 규칙에서 사용하도록합니다.

내가 문서를 가지고 말 : 내가 구문 분석

A 
B 

C 

을이 같은 :

#tokens 
rule :a do str("A") end 
rule :b do str("B") end 
rule :c do str("C") end 
rule :nl do str("\n") end 

# lines 
rule :a_line do a>>nl end 
rule :b_line do b>>nl end 
rule :c_line do c>>nl end 

# doc 
rule :doc do a_line>>b_line>>nl>>c_line 

은 아무것도 몰라한다로 "b_line"는 "\ n"의 모두를 소비하지 않습니다 것을 그것의 문맥에 대해서.

"space"가 "str ('') .repeat"로 정의되어있는 것으로 나타났습니다. 이것은 "str ('') .repeat (0)"의 줄임말로 0 번 일치 할 수 있습니다. 이것은 "space"를 선택적으로 만든다. 그러므로 "space.maybe"는 의미가 없다.