2017-08-03 60 views
2

我想從用戶獲取字符串,解析它,然後運行解析的命令。如何在LOGO中執行子字符串替換?

字符串輸入將類似於「F20N20E10L10」,保證沒有空格。

與替代像這樣的這種輸入我要轉換爲LOGO命令:

  • 「F」 →fd
  • 「N」 →seth 0 fd
  • 「E」 →seth 90 fd
  • 「L 「→lt 90 fd

所以上面的字符串輸入將是converte d這些LOGO命令:

fd 20 seth 0 fd 20 seth 90 fd 10 lt 90 fd 10

所有第四方言允許輸入,並解釋命令的字符串。

但我找不到任何與搜索和替換字符串操作。這是可能的任何LOGO的方言嗎?願意考慮任何。

謝謝您的閱讀。

回答

2

自從我寫了任何Logo以來已經有一段時間了,所以我不確定這是否是最簡單的方法,但這裏有一種方法可以實現。總的想法是,您可以使用字符串作爲字符列表,使用FIRST,LAST,BUTFIRSTBUTLAST來獲取字符串的不同部分。 (我測試這前兩個在線徽標解釋我能找到 - http://www.logointerpreter.com/turtle-editor.phphttp://www.calormen.com/jslogo/ - 它跑了兩個很好,但你可能需要爲其它徽標方言一些小的修改)

TO RUN_COMMANDS :commands 
    IF (EMPTY? :commands) [STOP] 

    MAKE "first_command (FIRST :commands) 
    MAKE "rest_of_commands (BUTFIRST :commands) 

    IF (NOT EMPTY? :rest_of_commands) [MAKE "split (GET_NUMBER :rest_of_commands ")] 
    MAKE "numeric_argument (LAST :split) 
    MAKE "rest_of_commands (FIRST :split) 

    RUN_SINGLE_COMMAND :first_command :numeric_argument 

    RUN_COMMANDS :rest_of_commands 
END 

TO MERGE_STRING :word :characters 
    IF (NOT EMPTY? :characters) [OP (MERGE_STRING (WORD :word (FIRST :characters)) (BUTFIRST :characters))] 
    OP :WORD 
END 

TO GET_NUMBER :word :number 
    IF (AND (NOT (EMPTY? :word)) (IS_DIGIT (FIRST :word))) [OP (SE (GET_NUMBER (BUTFIRST :word) (LPUT (FIRST :word) :number))] 
    OP (SE (MERGE_STRING " :word) (MERGE_STRING " :number)) 
END 

TO IS_DIGIT :character 
    OP (OR 
    :character = "0 
    :character = "1 
    :character = "2 
    :character = "3 
    :character = "4 
    :character = "5 
    :character = "6 
    :character = "7 
    :character = "8 
    :character = "9) 
END 

TO RUN_SINGLE_COMMAND :command :parameter 
    (PRINT_COMMAND :command :parameter) 
    IF (:command = "F) [FD :parameter] 
    IF (:command = "B) [BK :parameter] 
    IF (:command = "L) [LT 90 FD :parameter] 
    IF (:command = "R) [RT 90 FD :parameter] 
    IF (:command = "N) [SETH 0 FD :parameter] 
    IF (:command = "S) [SETH 180 FD :parameter] 
    IF (:command = "E) [SETH 90 FD :parameter] 
    IF (:command = "W) [SETH 270 FD :parameter] 
END 

TO PRINT_COMMAND :command :parameter 
    IF (:command = "F) [PRINT (SE "FD :parameter)] 
    IF (:command = "B) [PRINT (SE "BK :parameter)] 
    IF (:command = "L) [PRINT (SE "LT 90 "FD :parameter)] 
    IF (:command = "R) [PRINT (SE "RT 90 "FD :parameter)] 
    IF (:command = "N) [PRINT (SE "SETH 0 "FD :parameter)] 
    IF (:command = "S) [PRINT (SE "SETH 180 "FD :parameter)] 
    IF (:command = "E) [PRINT (SE "SETH 90 "FD :parameter)] 
    IF (:command = "W) [PRINT (SE "SETH 270 "FD :parameter)] 
END 

然後,嘗試運行:

RUN_COMMANDS "F20N20E10L10 

此打印並執行以下操作:

FD 20 
SETH 0 FD 20 
SETH 90 FD 10 
LT 90 FD 10 

一些說明

RUN_COMMANDS是主要功能。它:

  1. 提取從刺的第一個字母(我假設每個命令被縮寫爲單個字母)
  2. 呼叫GET_NUMBER從的開始提取數(其可以是多個字符)串。
  3. 通行證的單字母縮寫命令和數量RUN_SINGLE_COMMAND
  4. 遞歸重複

IS_DIGIT是內GET_NUMBER用來檢查一個字符是數字(儘管我敢打賭一些標誌方言有一個過程內置函數)

​​被使用,因爲我有一些多字符的單詞(「字」是標誌說話的字符串),我已經變成單字符單詞列表,我想將列表合併到單個Word中。不過,這實際上並不是必須的。

RUN_SINGLE_COMMAND執行從輸入字符串解析的每個單獨命令。我只是使用了一個大的IF語句,而不是像你所建議的那樣使用將字符串解釋爲代碼的函數。 (某些徽標方言可能有這樣的功能,但我不確定它是否是標準方式。)RUN_SINGLE_COMMAND也會調用PRINT_COMMAND,它會在運行時打印出未縮放的命令。


潛在的堆棧上溢

我用大量的遞歸的,因爲它是更地道的Logo,而且由於標誌方言往往沒有很多循環結構(比其他REPEAT)。但我以一種不小心的方式做到了這一點,因爲我只是快速寫下這些內容來給大家提供一個總體思路。特別是,我並不擔心堆棧溢出(沒有雙關語意圖),如果您提供了長輸入字符串,我認爲這可能會發生。爲了解決這個問題,你應該確保可以多次調用的任何遞歸路徑是一個尾部調用,這個Logo將優化掉。

一目瞭然,它看起來像RUN_COMMANDS是好的,但​​和GET_NUMBER反轉 - 而不是IF <condition> [<recursive_call>]其次OUTPUT <return_value>,倒不如做IF (NOT <condition>) [OUTPUT <return_value>]隨後<recursive_call>。測試堆棧溢出並應用此修復程序我已作爲練習留給讀者。 :)