【问题标题】:How to perform sub-string substitutions in LOGO?如何在 LOGO 中进行子字符串替换?
【发布时间】:2018-01-11 02:51:00
【问题描述】:

我想从用户那里获取字符串,解析它,然后运行解析的命令。

字符串输入类似于“F20N20E10L10”,保证没有空格。

我想将此输入转换为带有如下替换的 LOGO 命令:

  • “F”→fd
  • “N”→seth 0 fd
  • “E”→seth 90 fd
  • “L”→lt 90 fd

所以上面输入的字符串会被转换成这些LOGO命令:

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

所有 Forth 方言都允许输入和解释一串命令。

但我无法通过搜索和替换字符串操作找到任何内容。这在LOGO的任何方言中都可能吗?愿意考虑。

感谢您的阅读。

【问题讨论】:

    标签: replace string-matching logo-lang


    【解决方案1】:

    我已经有一段时间没有写任何徽标了,所以我不确定这是否是最简单的方法,但这是你可以做到的一种方法。一般的想法是您可以将字符串作为字符列表使用,使用FIRSTLASTBUTFIRSTBUTLAST 来获取字符串的不同部分。 (我在我能找到的前两个在线 Logo 解释器上进行了测试——http://www.logointerpreter.com/turtle-editor.phphttp://www.calormen.com/jslogo/——两者都运行良好,但您可能需要对其他 Logo 方言进行一些小改动。)

    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_DIGITGET_NUMBER 中用于检查字符是否为数字(尽管我敢打赌,某些 Logo 方言对此具有内置功能。)

    MERGE_STRING 被使用是因为我有一些多字符单词(“单词”是一个字符串的标志),我已经变成了单字符单词列表,我想将列表合并回一个字。不过,这实际上可能没有必要。

    RUN_SINGLE_COMMAND 执行从输入字符串解析的每个单独的命令。我只是使用了一个大的IF 语句,而不是使用一个将字符串解释为您建议的代码的函数。 (某些 Logo 方言可能有这样的功能,但我不确定是否有标准功能。)RUN_SINGLE_COMMAND 也调用 PRINT_COMMAND,它会在运行时打印出未缩写的命令。


    潜在的堆栈溢出

    我使用了大量递归,因为它更符合 Logo 的习惯,而且 Logo 方言通常没有很多循环结构(REPEAT 除外)。但是我做的很粗心,因为我写这篇文章只是为了给你一个大致的想法。特别是,我不担心堆栈溢出(不是双关语),我认为如果您提供了一个长输入字符串,可能会发生这种情况。为了解决这个问题,你应该确保任何可以任意多次调用的递归路径都是尾调用,Logo 会优化掉它。

    乍一看,RUN_COMMANDS 似乎很好,但 MERGE_STRINGGET_NUMBER 是相反的——而不是 IF <condition> [<recursive_call>] 后跟 OUTPUT <return_value>,最好是 IF (NOT <condition>) [OUTPUT <return_value>] 后跟 @ 987654347@。测试堆栈溢出并应用此修复程序作为练习留给读者。 :)

    【讨论】:

      猜你喜欢
      • 2011-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-23
      • 1970-01-01
      • 2011-07-25
      • 1970-01-01
      • 2016-09-29
      相关资源
      最近更新 更多