概述
正则表达式在任何一个编程语言中都是通用且必备的存在。Godot中也提供正则表达式功能。可以很好的对字符串进行高级处理。
以下就是Godot4中正则表达式的核心总结。
Godot正则表达式{RegEx:正则表达式的类{.compile("正则表达式"):编译正则表达式.search(源字符串):匹配一项.search_all(源字符串):匹配全部RegExMatch:单个匹配结果{.get_string():获取匹配的文本.get_string("分组名"):获取匹配中命名分组的文本.get_string(分组下标):获取匹配中指定下标分组的文本.get_start():获取匹配文本在源文本中的起始位置.get_end():获取匹配文本在源文本中的结束位置.get_group_count():获取匹配文本中组的数量使用方法:{1.创建RegEx实例:var regex=RegEx.new();2.编译正则模式:{regex.compile("正则表达式");regex.compile(r"正则表达式");3.获取第一个匹配结果:{result=regex.search(源字符串)=>RegExMatch;result.get_string();4.获取所有匹配结果:{regex.search_all(源字符串)=>Array[RegExMatch]; \scriptsize Godot正则表达式 \begin{cases} RegEx:正则表达式的类 \begin{cases} .compile("正则表达式"):编译正则表达式\\ .search(源字符串):匹配一项\\ .search\_all(源字符串):匹配全部\\ \end{cases} \\ RegExMatch:单个匹配结果 \begin{cases} .get\_string():获取匹配的文本\\ .get\_string("分组名"):获取匹配中命名分组的文本\\ .get\_string(分组下标):获取匹配中指定下标分组的文本\\ .get\_start():获取匹配文本在源文本中的起始位置\\ .get\_end():获取匹配文本在源文本中的结束位置\\ .get\_group\_count():获取匹配文本中组的数量\\ \end{cases} \\ 使用方法: \begin{cases} 1.创建RegEx实例:var \ regex = RegEx.new();\\ 2.编译正则模式: \begin{cases} regex.compile("正则表达式");\\ regex.compile(r"正则表达式");\\ \end{cases} \\ 3.获取第一个匹配结果: \begin{cases} result = regex.search(源字符串) => RegExMatch;\\ result.get\_string();\\ \end{cases} \\ 4.获取所有匹配结果: \begin{cases} regex.search\_all(源字符串) => Array[RegExMatch];\\ \end{cases} \\ \end{cases} \\ \end{cases} Godot正则表达式⎩⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎧RegEx:正则表达式的类{.compile("正则表达式"):编译正则表达式.search(源字符串):匹配一项.search_all(源字符串):匹配全部RegExMatch:单个匹配结果⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧.get_string():获取匹配的文本.get_string("分组名"):获取匹配中命名分组的文本.get_string(分组下标):获取匹配中指定下标分组的文本.get_start():获取匹配文本在源文本中的起始位置.get_end():获取匹配文本在源文本中的结束位置.get_group_count():获取匹配文本中组的数量使用方法:⎩⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎧1.创建RegEx实例:var regex=RegEx.new();2.编译正则模式:{regex.compile("正则表达式");regex.compile(r"正则表达式");3.获取第一个匹配结果:{result=regex.search(源字符串)=>RegExMatch;result.get_string();4.获取所有匹配结果:{regex.search_all(源字符串)=>Array[RegExMatch];
关于分组
正则表达式中括号括起来的就是一个分组,可以看作是一个子表达式。
get_string(0)
或get_string()
获取的是整个匹配的字符串get_string(1)
获取的是分组1的字符串get_string(2)
获取的是分组2的字符串,依次类推...get_start(1)
和get_end(1)
获取的就是分组1在源字符串中的起始和结束位置

在文本编辑框显示匹配文本
在Godot正则表达式总结的基础上,这里再提一个如何在TextEdit
中高亮匹配项文本的问题。
将字符串定位转为文本编辑框定位
Godot在TextEdit
和字符串之间的一个坑就是:
TextEdit
是用行和列的二维定位,而String
是一维定位,TextEdit
并未提供相关的方法来转换- 要实现
TextEdit
中对正则匹配字符串的选择,则需要将TextEdit
的text
中的一维定位,转成TextEdit
光标的行列定位形式。 - 方法也很简单,行数是其之前字符串中的
\n
数量,列数是其之前字符串中最后一行的文本长度。
swift
# 将字符串的1维定位转为TextEdit中的行列定位
func get_edit_pos(sttr:String,pos) -> Vector2:
var edit_pos:Vector2
var pre_str = sttr.left(pos) // 位置之前的字符串
edit_pos.y = pre_str.count("\n") // 所在行
var arr:PackedStringArray = pre_str.split("\n")
edit_pos.x = arr[arr.size()-1].length() // 所在列
return edit_pos
获取匹配的起始和结束位置
使用RegExMatch
的get_start()
和get_end()
可以获取匹配文本在源字符串中的起始和结束位置,通过上述的转化方式便可以获得在文本框中的起始和结束位置。
在文本框中选中匹配文本
通过TextEdit
的select(),传入起始光标位置和结束光标位置,便可以选中匹配文本。
swift
# 在文本编辑框中选中
edit.select(start.y,start.x,end.y,end.x)
关于正则匹配的基础函数封装
以下是我封装的两个函数,用于方便的获取匹配和在TextEdit
中显示匹配的项。
swift
# 获取匹配的结果数组
func get_matshs(source_str:String,reg:String) -> Array[RegExMatch]:
var regex = RegEx.new()
regex.compile(reg)
return regex.search_all(source_str) # 获取匹配结果
# 选中文本编辑器中的匹配项
func hilight_match(
edit:TextEdit, # 文本编辑器
reg:String, # 正则表达式
match_idx:=0, # 匹配的索引
gup_idx:= 0 # 分组索引
) -> void:
var matchs:Array[RegExMatch] = get_matshs(edit.text,reg) # 获取匹配结果
# 当前匹配项
var mtch:RegExMatch
if matchs.size()>0:
mtch = matchs[clampi(match_idx,0,matchs.size()-1)]
# 转化字符串中的1D位置为文本框中的2D位置
var start:Vector2 = get_edit_pos(edit.text,mtch.get_start(gup_idx))
var end:Vector2 = get_edit_pos(edit.text,mtch.get_end(gup_idx))
# 在文本编辑器中选中
edit.select(start.y,start.x,end.y,end.x)
其中,hilight_match()
中:
- 使用
clampi()
限定match_idx的范围
测试
编写一个简单的界面,来测试效果:

代码如下:
swift
extends Control
var idx := 0 # 当前索引
@onready var reg_txt: LineEdit = %regTxt
@onready var sourse_txt: CodeEdit = %sourseTxt
@onready var matchs_txt: CodeEdit = %matchsTxt
@onready var gup_index: SpinBox = %gupIndex
...上述函数
# 查找 - 显示第一项
func _on_find_btn_pressed() -> void:
idx = 0
hilight_match(sourse_txt,reg_txt.text,idx,int(gup_index.value))
# 下一项
func _on_nex_btn_pressed() -> void:
var size = get_matshs(sourse_txt.text,reg_txt.text).size()
idx = wrapi(idx + 1,0,size)
hilight_match(sourse_txt,reg_txt.text,idx,int(gup_index.value))
其中:
- 使用
wrapi
在匹配结果中实现下标循环。