我如何解析 Netlogo 中的字符串?
How can I parse a string in Netlogo?
上下文
对于我的模型,我希望有一个输入,用户可以在其中输入一系列值。
例如
我想从上面显示的输入中得到一个包含五个数字的列表,例如[0.5 0.2 0 0.2 0.5]
,这样我就可以使用他们输入的数字进行一些计算。
问题
不幸的是,如果我将类型设置为字符串,像上面那样设置输入将吐出 "0.5 0.2 0 0.2 0.5"
。如果我将类型设置为数字,它将只允许输入一个数字。
那么,我如何根据 space(即“”)解析字符串?我也对替代方案持开放态度,尽管我更愿意将其保留在 Netlogo 中(例如,不读取值的文本文件)以使其更容易更改,因为我怀疑它会被广泛使用。
我试过的
我试过使用read-from-string
,但它也不喜欢像上面那样输入一系列数字。我还尝试使用字符串扩展 (https://github.com/NetLogo/String-Extension) 中的 explode
函数,但我的 Netlogo (6.2.0) 版本不喜欢该扩展中的 API,因此不会允许我使用它。
我是 NetLogo 的新手,如果我的问题很愚蠢或者我没有说清楚,我很抱歉!
您可以结合使用 position
、substring
、read-from-string
和 fput
。
这是工作流程:
- 创建一个循环,只要字符串包含多个数字(= 只要它包含至少一个 space,使用
position " " string
检查);
- 提取从第一个字符到排除的第一个 space 的子字符串(用
substring
完成);
- 将该子字符串作为数值读取(使用
read-from-string
)并将其添加到 list-of-numbers
(使用 fput
);
- 删除字符串中的第一个数字(使用
position " " string
、repeat
和but-first
)并再次开始循环;
- 当循环条件为
FALSE
时,表示字符串中只剩下一个数字。将最后一个数字(即整个剩余字符串)添加到循环外的 list-of-numbers
,一切都完成了。
下面的程序是一个报告程序,它执行此工作流并报告从字符串中读取的值列表(它只需要在界面中有一个 user-string
输入框):
to-report convert-user-string [str]
let temp-string user-string
let list-of-numbers (list)
while [position " " temp-string != FALSE] [
let next-number-as-string (substring temp-string 0 position " " temp-string)
set list-of-numbers lput (read-from-string next-number-as-string) (list-of-numbers)
repeat (position " " temp-string + 1) [
set temp-string (but-first temp-string)
]
]
set list-of-numbers lput (read-from-string temp-string) (list-of-numbers)
report list-of-numbers
end
例如:
observer> set user-string "0.5 0.2 0 0.2 0.5"
observer> show user-string
observer: "0.5 0.2 0 0.2 0.5"
observer> show convert-user-string user-string
observer: [0.5 0.2 0 0.2 0.5]
我在上面发布的程序是我制作的初始代码的精简版,我将在下面留下大量评论:
globals [
list-of-numbers ; The list where values from the input string will be stored.
temp-string ; A temporary variable being the alter-ego of 'user-list'. This is needed because
; the 'trim-string-to-next-nonspace' procedure won't let me change the value of
; 'user-string' directly (I am not sure why, anyone please feel free to say if I'm
; missing something here) but also because you might want to keep the value of the
; user input intact - hence we use this 'temp-string' to trim the string without worries.
]
to convert-user-string [str]
; As long as there are at least two numbers in the string (identified by the presence of at least one
; space), the while loop extracts the first number with 'substring' and then assigns it as a numeric
; value to 'list-of-numbers' by using 'read-from-string' and 'lput'. At that point, it trims the
; string up to the next non-space character.
; When there is only one number left in the string (identified by the absence of spaces in the string),
; the 'more-than-one-number-in-string? temp-string'condition evaluates as 'FALSE' and the while loop
; stops. At that point, the last line of code adds what is left of the string (i.e. the last number)
; to the 'list-of-numbers' list.
set list-of-numbers (list) ; Initiating this variable as a list in order to be able to use 'lput'.
set temp-string user-string
while [more-than-one-number-in-string? temp-string] [
let next-number-as-string (substring temp-string 0 position-of-next-space temp-string)
set list-of-numbers lput (read-from-string next-number-as-string) (list-of-numbers)
trim-string-to-next-nonspace temp-string
]
set list-of-numbers lput (read-from-string temp-string) (list-of-numbers)
end
to-report more-than-one-number-in-string? [str]
; This reporter is needed as a condition for the while loop in 'convert-user-string'. The reason is that
; the 'position' command (used by the 'position-of-next-space' procedure) reports either a number (i.e.
; the position of the character in the given string) or 'FALSE' (in case the item is not present in the
; string). Therefore, this procedure is needed in order to get either TRUE or FALSE to be used in the
; while condition.
ifelse (position-of-next-space str = FALSE)
[report FALSE]
[report TRUE]
end
to-report position-of-next-space [str]
; Simply reporting the position of the next space in the string. Note that positions (indexes) in NetLogo
; are numbered starting from 0.
report position " " str
end
to trim-string-to-next-nonspace [str]
; By using 'but-first' repeatedly, this procedure gets rid of the first number (which has already been stored
; in 'list-of-numbers' by the 'convert-user-string' procedure) and the following space in the string.
; Note that the '+ 1' bit is needed because the count of positions in NetLogo starts from 0 for the first item.
let x temp-string
repeat (position-of-next-space temp-string + 1) [
set x (but-first x)
]
set temp-string x
end
根据 the docs on it, read-from-string
can parse a list of literal values. The issue you are having is that a NetLogo list literal must have square brackets to open and close, as per the Constant Lists section of the Programming Guide。因此,您需要做的就是将 [
和 ]
添加到用户的输入中。
to test
let s "0.5 0.2 0 0.2 0.5"
let l read-from-string (word "[" s "]")
show l
show item 2 l
end
输出:
observer> test
observer: [0.5 0.2 0 0.2 0.5]
observer: 0
不过我要提醒的是,用户很容易输入不同格式的数字,例如 0, 2, 3, 5.0
,使用逗号分隔值。检查转换是否实际工作是明智的,因为您从失败 read-from-string
中得到的错误消息可能对模型用户没有帮助。
查看 the CSV extension's csv:from-row
primative。
extensions [ csv ]
to test
let s "0.5 0.2 0 0.2 0.5"
let l (csv:from-row "0.5 0.2 0 0.2 0.5" " ")
show l
show item 2 l
end
上下文
对于我的模型,我希望有一个输入,用户可以在其中输入一系列值。
例如
我想从上面显示的输入中得到一个包含五个数字的列表,例如[0.5 0.2 0 0.2 0.5]
,这样我就可以使用他们输入的数字进行一些计算。
问题
不幸的是,如果我将类型设置为字符串,像上面那样设置输入将吐出 "0.5 0.2 0 0.2 0.5"
。如果我将类型设置为数字,它将只允许输入一个数字。
那么,我如何根据 space(即“”)解析字符串?我也对替代方案持开放态度,尽管我更愿意将其保留在 Netlogo 中(例如,不读取值的文本文件)以使其更容易更改,因为我怀疑它会被广泛使用。
我试过的
我试过使用read-from-string
,但它也不喜欢像上面那样输入一系列数字。我还尝试使用字符串扩展 (https://github.com/NetLogo/String-Extension) 中的 explode
函数,但我的 Netlogo (6.2.0) 版本不喜欢该扩展中的 API,因此不会允许我使用它。
我是 NetLogo 的新手,如果我的问题很愚蠢或者我没有说清楚,我很抱歉!
您可以结合使用 position
、substring
、read-from-string
和 fput
。
这是工作流程:
- 创建一个循环,只要字符串包含多个数字(= 只要它包含至少一个 space,使用
position " " string
检查); - 提取从第一个字符到排除的第一个 space 的子字符串(用
substring
完成); - 将该子字符串作为数值读取(使用
read-from-string
)并将其添加到list-of-numbers
(使用fput
); - 删除字符串中的第一个数字(使用
position " " string
、repeat
和but-first
)并再次开始循环; - 当循环条件为
FALSE
时,表示字符串中只剩下一个数字。将最后一个数字(即整个剩余字符串)添加到循环外的list-of-numbers
,一切都完成了。
下面的程序是一个报告程序,它执行此工作流并报告从字符串中读取的值列表(它只需要在界面中有一个 user-string
输入框):
to-report convert-user-string [str]
let temp-string user-string
let list-of-numbers (list)
while [position " " temp-string != FALSE] [
let next-number-as-string (substring temp-string 0 position " " temp-string)
set list-of-numbers lput (read-from-string next-number-as-string) (list-of-numbers)
repeat (position " " temp-string + 1) [
set temp-string (but-first temp-string)
]
]
set list-of-numbers lput (read-from-string temp-string) (list-of-numbers)
report list-of-numbers
end
例如:
observer> set user-string "0.5 0.2 0 0.2 0.5"
observer> show user-string
observer: "0.5 0.2 0 0.2 0.5"
observer> show convert-user-string user-string
observer: [0.5 0.2 0 0.2 0.5]
我在上面发布的程序是我制作的初始代码的精简版,我将在下面留下大量评论:
globals [
list-of-numbers ; The list where values from the input string will be stored.
temp-string ; A temporary variable being the alter-ego of 'user-list'. This is needed because
; the 'trim-string-to-next-nonspace' procedure won't let me change the value of
; 'user-string' directly (I am not sure why, anyone please feel free to say if I'm
; missing something here) but also because you might want to keep the value of the
; user input intact - hence we use this 'temp-string' to trim the string without worries.
]
to convert-user-string [str]
; As long as there are at least two numbers in the string (identified by the presence of at least one
; space), the while loop extracts the first number with 'substring' and then assigns it as a numeric
; value to 'list-of-numbers' by using 'read-from-string' and 'lput'. At that point, it trims the
; string up to the next non-space character.
; When there is only one number left in the string (identified by the absence of spaces in the string),
; the 'more-than-one-number-in-string? temp-string'condition evaluates as 'FALSE' and the while loop
; stops. At that point, the last line of code adds what is left of the string (i.e. the last number)
; to the 'list-of-numbers' list.
set list-of-numbers (list) ; Initiating this variable as a list in order to be able to use 'lput'.
set temp-string user-string
while [more-than-one-number-in-string? temp-string] [
let next-number-as-string (substring temp-string 0 position-of-next-space temp-string)
set list-of-numbers lput (read-from-string next-number-as-string) (list-of-numbers)
trim-string-to-next-nonspace temp-string
]
set list-of-numbers lput (read-from-string temp-string) (list-of-numbers)
end
to-report more-than-one-number-in-string? [str]
; This reporter is needed as a condition for the while loop in 'convert-user-string'. The reason is that
; the 'position' command (used by the 'position-of-next-space' procedure) reports either a number (i.e.
; the position of the character in the given string) or 'FALSE' (in case the item is not present in the
; string). Therefore, this procedure is needed in order to get either TRUE or FALSE to be used in the
; while condition.
ifelse (position-of-next-space str = FALSE)
[report FALSE]
[report TRUE]
end
to-report position-of-next-space [str]
; Simply reporting the position of the next space in the string. Note that positions (indexes) in NetLogo
; are numbered starting from 0.
report position " " str
end
to trim-string-to-next-nonspace [str]
; By using 'but-first' repeatedly, this procedure gets rid of the first number (which has already been stored
; in 'list-of-numbers' by the 'convert-user-string' procedure) and the following space in the string.
; Note that the '+ 1' bit is needed because the count of positions in NetLogo starts from 0 for the first item.
let x temp-string
repeat (position-of-next-space temp-string + 1) [
set x (but-first x)
]
set temp-string x
end
根据 the docs on it, read-from-string
can parse a list of literal values. The issue you are having is that a NetLogo list literal must have square brackets to open and close, as per the Constant Lists section of the Programming Guide。因此,您需要做的就是将 [
和 ]
添加到用户的输入中。
to test
let s "0.5 0.2 0 0.2 0.5"
let l read-from-string (word "[" s "]")
show l
show item 2 l
end
输出:
observer> test
observer: [0.5 0.2 0 0.2 0.5]
observer: 0
不过我要提醒的是,用户很容易输入不同格式的数字,例如 0, 2, 3, 5.0
,使用逗号分隔值。检查转换是否实际工作是明智的,因为您从失败 read-from-string
中得到的错误消息可能对模型用户没有帮助。
查看 the CSV extension's csv:from-row
primative。
extensions [ csv ]
to test
let s "0.5 0.2 0 0.2 0.5"
let l (csv:from-row "0.5 0.2 0 0.2 0.5" " ")
show l
show item 2 l
end