不同长度的Fortran子字符串比较存在问题

ker*_*r2x 2 fortran gfortran

我正在循环阅读stdin,并与一堆“ if”进行比较,以根据输入决定要做什么。

这是一段简短的代码:

CHARACTER (len= :), allocatable :: input
CHARACTER (len=4096) :: inbuffer            ! frustrating but... well, fortran :3

DO

    ! get input
    READ(*, '(a)') inbuffer     ! because apparently you can't have allocation on read so you can't just read "input". meh.
    input = TRIM(inbuffer)
    CALL debug_log(input)

    IF(input .EQ. 'uci') THEN
        CALL debug_log("   printing uci info")

    !isready
    ELSE IF(input .EQ. 'isready') THEN
        CALL debug_log("   isready -> readyok")
        WRITE(*, '(a)') "readyok"

    !ucinewgame
    ELSE IF(input .EQ. 'ucinewgame') THEN
        CALL debug_log("not implemented : reset board and start a new game")

    !position
    ELSE IF(input(1:8) .EQ. 'position') THEN
        CALL debug_log("not implemented : set position")

    !quit -> exit main loop
    ELSE IF(input .EQ. 'quit') THEN
        CALL debug_log("   quit command issued, exiting main loop")
        EXIT

    !non uci command
        !nothing yet

    !unknown command
    ELSE
        CALL debug_log("   ignoring invalid command")
    END IF

end do
Run Code Online (Sandbox Code Playgroud)

输入将期望像“位置123 23415等...”这样的命令

如果键入“ posi”,则表示这是预期的无效命令。

如果我键入“ position”,则表示它也没有按预期实现。

但是

  • 如果我输入“ position”:我没有实现
  • 后跟“ posi”:表示“未实现”,而不是“无效命令”

我的猜测是,即使输入只有4个字符,它也会读取8个字符,并且由于上一个命令是“ position”,因此它的位置为+ position = position

这是一些日志来演示:

** opening debug file : 20181111 / 223418.127
223418.127 : Initializing Fortiche engine
223418.129 : Entering main loop
223420.859 : posi
223420.859 :    ignoring invalid command
223426.467 : xxxxtion
223426.467 :    ignoring invalid command
223430.498 : posi
223430.498 : not implemented : set position
223437.323 : xxxxxxxxx
223437.323 :    ignoring invalid command
223439.418 : posi
223439.418 :    ignoring invalid command
223443.979 : position
223443.979 : not implemented : set position
223447.122 : quit
223447.122 :    quit command issued, exiting main loop
223447.122 : closing, bye
Run Code Online (Sandbox Code Playgroud)

xxxxtion + posi =位置

这显然是错误的,但我可以理解它是如何最终结束的。

我是否应该使用.EQ以外的名称?当我打印输入时,显然不会打印输入+内存中留下的任何垃圾。但是在比较长度可能不同的字符串时会这样做。

我该怎么做才能解决这个问题?

我什至没有开始进行核心解析,我已经遇到了问题。

我在Windows上使用GNU Fortran。

是的,它是UCI的通用国际象棋界面。

编辑:完整源代码:https : //github.com/ker2x/fortiche(评论第107和108行的肮脏黑客,以重现该问题)

Ian*_*anH 5

子字符串引用的开始和结束位置必须在字符串的范围内。

您不能避免在子字符串引用之前长度小于8的字符串input(1:8) .eq. 'position'

如果输入的字符少于八个字符,则您的程序将不合格,然后任何事情都可能发生,其中任何事情都非常合理地包括您所看到的行为。

运行时调试选项可能有助于捕获此编程错误,具体取决于编译器的功能。

  • 两个注释/建议:Fortran 的 `trim()` 函数更适合任何其他语言中的 `rtrim()`(仅修剪尾随空格)。`adjustl()` 将字符串左移,将前导空格附加到字符串的末尾,使其与原始长度相同;`trim(adjustl(inbuffer))` 实现了正确的 `trim` 函数,删除了前导和尾随空格。同样,您可以使用 len_trim(audjustl(inbuffer)) 来获取(正确)修剪的字符串的长度。其次,为了清楚起见,请考虑使用 Fortran 的“select/case”结构而不是级联的“if/then/elseif”。 (2认同)