스크립트 언어 쿠인

8580 단어 Kuin
쿠인 어드벤트 캘린더가 2018년 4일째여서 좋은 아침입니다(생각난 소재가 11/26이라 썼습니다).
   
Kuin 언어에는 Kuin 편집기라는 편집기가 포함되어 있습니다.그나저나 쿠인 도서관도kn 파일로 기재한 거 아세요?

예를 들어, cui 라이브러리는 sys\cui입니다.kn이 기술한 것이지만 벚꽃 편집기에서 열면 이런 느낌이다.

그리고 쿠인 편집기에서 이 녀석을 열어.

이것을 다른 폴더에 저장한 파일에서 벚꽃 편집기를 다시 엽니다.

예, Kuin 편집기에서 저장을 열면 파일의 축소가 미묘하게 변할 수 있다는 것을 알고 싶습니다.
그럼 쿠엔의 issue를 켜서 카이나에게 보고하고 쿠엔 편집자에게 수정을 시킬 수 있는데 좀 미숙하네요.다른 방법이 있습니까?프로그래머가 자주 하는 방법으로는 Perl, Ruby 등 스크립트 언어를 써서 축소를 수정할 수 있다.하지만 Windows에 스크립트 언어를 설치하는 것은 매우 번거롭다.나는 직장에서 집으로 돌아가는 길에 갑자기 생각이 났다.
"맞다! 쿠인으로 대본 쓰면 되잖아!"
step1. 파일 경로 가져오기
그럼 뭐부터 시작할까요?파일 이름을 지정하면 파일 경로를 표시하는 프로그램을 만듭니다.
test1.kn
func main()
    if(^lib@cmdLine() <> 1)
        do cui@print("エラー: ファイル名を1つ指定してください。\n")
        ret
    end if
    do cui@print(file@getCurDir() ~ lib@cmdLine()[0] ~ "\n")
end func
데스크톱에서 이 파일을 컴파일하고 실행하면 정확한 결과를 얻을 수 있습니다.

아는 사람이 있을 것 같으니 먼저 설명해 주세요.
lib@cmdLine()는 프로그램이 지정한 명령행 매개 변수를 문자열 배열로 가져오는 것을 말한다.예컨대 a.exe abc라면lib@cmdLine()의 반환 값은 [a','b','c']입니다.a.exe 매개 변수가 없는 경우lib@cmdLine()의 반환 값은 []입니다.이 때, 그룹에서 원소를 꺼내려면 오류가 발생하기 때문에if문장을 쓰고 오류 정보를 출력해야 합니다.
file@getCurDir() 함수가 현재 디렉토리를 가져옵니다.명령 프롬프트 앞에 쓴 폴더 경로입니다.현재 디렉터리라는 개념이 존재하기 때문에 명령 알림의 사용자는 명령을 실행할 때 긴 파일 경로를 쓰지 않을 수 있습니다.
~는 배열을 연결하는 연산자입니다.Kuin에서 문자열은 문자의 배열이기 때문에 이 연산자를 사용할 수 있습니다.
step2. 파일 내용을 표시하는 프로그램 만들기
그러면 파일을 읽고 내용을 출력하는 프로그램을 만듭시다.
cat.kn
func main()
    ; コマンドライン引数が1つでなければエラー
    if(^lib@cmdLine() <> 1)
        do cui@print("エラー: ファイル名を1つ指定してください。\n")
        ret
    end if

    ; ファイルを開く
    var rd: file@Reader :: file@makeReader(
    |file@getCurDir() ~ lib@cmdLine()[0])

    while(!rd.term()) {ファイルの終端でなければ}
        do cui@print(rd.readLine() ~ "\n") {1行読んで出力する}
    end while

    ; ファイルを閉じる
    do rd.fin()
end func
이 프로그램을 컴파일하고 실행할 때 파일을 정확하게 읽고 컨트롤러에 출력할 수 있습니다.

step3. 정규 표현식 쓰기
그럼 명령줄을 잠시 놓고 정규 표현식을 써 보세요.
match1.kn
func check(rg: regex@Regex, str: []char)
    if(rg.match(str) <>& null)
        do dbg@print(str ~ ": matched\n")
    else
        do dbg@print(str ~ ": unmatched\n")
    end if
end func

func main()
    var rg: regex@Regex
    |:: regex@makeRegex("([\\t\\+]*)func(\\[.*\\])(\\S.*)")
    do @check(rg, "func") {unmatched}
    do @check(rg, "func[]abc(") {matched}
    do @check(rg, "func\\[\\]\\(") {unmatched}
    do @check(rg, "func[] abc(") {unmatched}
    do @check(rg, "\t+func[_abc, _def]ghi(jkl)") {matched}
end func
메이크 레지스트로 주문 같은 걸 써놨어.이 주문은 정규 표현식이라고 한다.
  • \t 맞춤법 테이블 문자.
  • \+일치+.
  • [\t\\+]는 테이블 문자 또는 +를 맞춤형으로 만듭니다.
  • [\t\\+]*은(는) 0자 이상의 레이블 문자 또는 +와 일치합니다.
  • 즉, 이것은 함수가 'func' 를 정의하기 전의 문자 집합을 나타낸다.end func에는 적합하지 않습니다.
  • \[일치[.
  • \\\일치].
  • .*임의의 문자열과 일치합니다.
  • \\[.*\\]은[과] 사이에 있는 문자열과 일치합니다.
  • func[foo option]bar(baz)의 기술[foo option]은 사양에 공개되지 않은 함수를 지정하는 옵션입니다.\섹션을 [.*\\\]로 일치시킵니다.
  • \S는 공백이 아닌 문자와 일치합니다.
  • .*임의의 문자열과 일치합니다.
  • 즉,\\S.*는 공백이 아닌 문자로 시작하는 문자열과 일치합니다.
    그러면 방금 전의 정규 표현식은 몇 개의 괄호로 구분되었다.이거 어떻게 써요?
    match2.kn
    func main()
        var rg: regex@Regex
        |:: regex@makeRegex("([\\t\\+]*)func(\\[.*\\])(\\S.*)")
        var m: [][]char :: rg.match("\t+func[_abc, _def]ghi(jkl)")
        for i(0, ^m - 1)
            do dbg@print(i.toStr() ~ ": " ~ m[i] ~ "\n")
        end for
    end func
    
    이 프로그램의 출력 결과는 다음과 같다.

    즉 정규 표현식의 대상에서 match 방법을 호출할 때 0번째는 전체 문자열이고 1번째는 괄호로 묶은 하위 문자열이다.만약 이걸로 다시 축소한다면 프로그램의 중심 부분은 완성될 것이다.
    match3.kn
    func main()
        var rg: regex@Regex
        |:: regex@makeRegex("([\\t\\+]*)func(\\[.*\\])(\\S.*)")
    
        var input: []char :: "\t+func[_abc, _def]ghi(jkl)"
        var m: [][]char :: rg.match(input)
        var output: []char :: m[1] ~ "func " ~ m[2] ~ " " ~ m[3]
    
        do dbg@print(output ~ "\n")
    end func
    

    step4. 프로그램 연결하기
    그럼 step2와 step3을 연결해서 프로그램을 완성하세요.
    indent.kn
    func main()
        ; コマンドライン引数が1つでなければエラー
        if(^lib@cmdLine() <> 1)
            do cui@print("エラー: ファイル名を1つ指定してください。\n")
            ret
        end if
    
        ; 正規表現オブジェクトの作成
        var rg: regex@Regex
        |:: regex@makeRegex("([\\t\\+]*)func(\\[.*\\])(\\S.*)")
    
        ; ファイルを開く
        var rd: file@Reader :: file@makeReader(
        |file@getCurDir() ~ lib@cmdLine()[0])
    
        while(!rd.term()) {ファイルの終端でなければ}
            var line: []char :: rd.readLine() {1行読む}
            var m: [][]char :: rg.match(line) {マッチさせてみる}
            if(m <>& null) {マッチした場合}
                ; インデントする
                do cui@print(m[1] ~ "func " ~ m[2] ~ " " ~ m[3] ~ "\n")
            else {マッチしなかった場合}
                ; そのまま出力する
                do cui@print(line ~ "\n")
            end if
        end while
    
        ; ファイルを閉じる
        do rd.fin()
    end func
    

    최초의 동작이 정확하고, 뒤의 출력이 그대로 있다.보아하니 함수 정의 내의 배열형의 기술이 방해가 되는 것 같다.이 녀석을 상대하기 위해서 나는 m[2]에서 그를 배제할 것이다.
    indent.kn
    func main()
        ; コマンドライン引数が1つでなければエラー
        if(^lib@cmdLine() <> 1)
            do cui@print("エラー: ファイル名を1つ指定してください。\n")
            ret
        end if
    
        ; 正規表現オブジェクトの作成
        var rg: regex@Regex
        |:: regex@makeRegex("([\\t\\+]*)func(\\[[^\\[\\]]*\\])(\\S.*)")
    
        ; ファイルを開く
        var rd: file@Reader :: file@makeReader(
        |file@getCurDir() ~ lib@cmdLine()[0])
    
        while(!rd.term()) {ファイルの終端でなければ}
            var line: []char :: rd.readLine() {1行読む}
            var m: [][]char :: rg.match(line) {マッチさせてみる}
            if(m <>& null) {マッチした場合}
                ; インデントする
                do cui@print(m[1] ~ "func " ~ m[2] ~ " " ~ m[3] ~ "\n")
            else {マッチしなかった場合}
                ; そのまま出力する
                do cui@print(line ~ "\n")
            end if
        end while
    
        ; ファイルを閉じる
        do rd.fin()
    end func
    

    정규 표현식의 기술만 변경합니다.
  • \\[.\\\]일치].
  • [\\[\\\]이(가) [또는] 일치합니다.
  • [^\[\\\]이(와) 이외에 일치합니다.
  • [^\[\\\]*는 [와]가 없는 문자열과 일치한다.
  • 따라서 프로그램의 정확한 운행.
    총결산
    어때요?몰라요?이 기사의 내용에 대해 궁금한 점이 있다면 약초춘남의 트위터 계정@HaruoWakakusa에 올려주세요.

    좋은 웹페이지 즐겨찾기