自己动手实现 Split:社区字符串工具函数
「怎么把 "red,green,blue" 按逗号拆开?」——这是论坛上的高频问题,而答案出人意料:Verse 标准库里没有 Split,你得自己写。好消息是,这个轮子只有十几行,还能把第 6 课的全部技能串起来练一遍。
一、Split 缺席:不是你没找到,是真的没有
写惯了 Python / JavaScript 的同学,遇到「按分隔符拆字符串」时手指会自动敲出 Split。然后 Verse 编译器一脸茫然——标准库里确实没有这个函数。在蓝图里做过字符串处理的同学,遇到「按分隔符拆字符串」多半会去 String 节点库找个 Split 节点。可到了 Verse,标准库里确实没有这个现成功能——点 Compile 也变不出来。Epic 开发者论坛上有人专门发帖问「any way to split a string?」,版主的回答很干脆:官方文档中不存在该方法,请自己实现。同样缺席的还有 Replace、Contains、ToUpper / ToLower——Verse 的字符串工具箱克制到近乎禁欲。
但换个角度看,这是一份送上门的练习题。因为 string 的真身是 []char(字符数组),数组能干的事它全能干:for 逐字符遍历、.Length 数长度、失败上下文里按下标取值。再加上插值拼接 set Word += "{Ch}",手写一个 Split 的所有零件,第 6 课其实已经发给你了。
但换个角度看,这是一份送上门的练习题。因为 string 的真身是 []char(字符数组),凡是数组能干的,它全能干:用 ForEach 逐个字符遍历、用 .Length 数长度、在 Branch(if)里按下标安全取一个字符。再加上用插值把字符拼进词里(set Word += "{Ch}" 就是接一个 Set 节点),手写一个 Split 的所有零件,第 6 课其实已经发给你了。
二、社区标准写法:逐字符扫描 + 拼词
思路就是人肉断句:从头到尾扫一遍字符,不是分隔符就拼进当前词;一碰到分隔符,就把攒好的词丢进结果数组,再从零开始攒下一个。
Split(Text:string, Separator:char):[]string =
var Words:[]string = array{}
var Word:string = ""
for (Ch : Text):
if (Ch = Separator):
# 撞上分隔符:当前词收工,入库
set Words = Words + array{Word}
set Word = ""
else:
# 普通字符:用插值拼进当前词
set Word += "{Ch}"
# 收尾:最后一个词后面没有分隔符,别忘了它
set Words = Words + array{Word}
Words
逐行拆解,每一行都是第 6 课的老熟人:
▢ for (Ch : Text)——string 是 []char,所以能像数组一样遍历,每轮拿到一个 char。
◇ if (Ch = Separator)——字符比较用可失败的 =,所以必须住在 if 这个失败上下文里。
△ set Word += "{Ch}"——char 借插值转成 string 再拼接,社区实现里最经典的一手。
★ Words + array{Word}——数组加法把新词接在结果尾部;最后一行裸写 Words,利用隐式返回把结果交出去。
▢ for (Ch : Text)——string 就是 []char(字符数组),所以能像 ForEach 一样逐个字符跑,每轮 Loop Body 拿到一个字符 char。
◇ if (Ch = Separator)——判断两个字符是否相等,这是个「可能不成立」的判断,所以要放进 Branch(Verse 写作 if):相等就走一条线,不等走另一条。
△ set Word += "{Ch}"——单个字符不能直接接到文字上,先用花括号插值把它转成 string,再用 Set 节点接到当前词尾,社区实现里最经典的一手。
★ Words + array{Word}——数组相加,把新词接到结果数组尾部;最后一行光写一个 Words,就是把它当作这个蓝图函数的返回值直接交出去(Verse 不用专门喊 return)。
调用起来长这样:
using { /Fortnite.com/Devices }
using { /UnrealEngine.com/Temporary/Diagnostics }
split_demo_device := class(creative_device):
OnBegin<override>()<suspends>:void =
Colors := Split("red,green,blue", ',')
for (Color : Colors):
Print("拆出:{Color}")
读图翻译:游戏一开始(Event BeginPlay),调用刚写的 Split 函数,把 "red,green,blue" 按逗号 ',' 拆成一个字符串数组 Colors;再用 ForEach(for)逐个遍历,每个都用 Print String 打出「拆出:xxx」。
日志会依次打出 拆出:red、拆出:green、拆出:blue。一个细节值得注意:这个实现在收尾时无条件把最后一个词入库,所以 Split("a,b,", ',') 会得到 a、b 和一个空串——和 JavaScript 的行为一致和大多数语言里的 Split 一致。想过滤空词,在入库前加一个 if (Word.Length > 0) 即可,顺手就能改。
Epic 官方社区的代码片段区也有一份现成的「Verse String Split Function」,思路与上面完全一致;论坛帖子里的版本还演示了用失败性下标 Text[Index] 代替 for 的写法。论坛帖子里的版本还演示了另一种写法:不用 ForEach,而是用「按下标取值」Text[Index] 一个位置一个位置地取(越界取不到就停)。两种都值得读一遍——它们是最地道的社区 Verse 风格样本。
更重要的是,这套「逐字符扫描 + 状态累积」的套路是万金油:把比较条件稍作改动,就能派生出一整族标准库里缺席的工具——Contains(找到目标序列就提前收工)、Replace(把匹配片段换成新词再拼回去)、Trim(跳过首尾空白字符)。亲手写完一次 Split,剩下的字符串方法你基本都能自给自足,再也不用眼馋其他语言的工具箱了。
三、随堂小测 ★
为什么 for (Ch : Text) 能逐字符遍历一个 string?为什么 for (Ch : Text)(蓝图里的 ForEach Loop)能逐字符遍历一个 string?
实现里的 set Word += "{Ch}" 这一行,在干什么?实现里的 set Word += "{Ch}"(一个 Set 节点)这一行,在干什么?
来源与延伸
本文整理自 Epic 开发者论坛与官方社区代码片段:
▢ 论坛讨论:Any way to split a string? ↗
◇ 官方社区片段:Verse String Split Function ↗