在 Golang 中,要完美地使用 regexp 解析 UBB 代码中的 video 播放标签,我们需要考虑几种常见的 UBB video 标签格式,并编写一个能够匹配这些格式的正则表达式。
UBB (Ultimate Bulletin Board) 的 video 标签格式通常有以下几种:
* <video src="http://example.com/video.mp4" style="max-width:500px;min-width:320px;height:auto;display:block;margin:0 auto;" controls></video>
* <video src="http://example.com/video.mp4" width:height></video>
* <video src="http://example.com/video.mp4" url></video> (不太常见,但需要考虑)
* <video src="http://example.com/video.mp4" width:height:url></video> (非常少见,但为了全面考虑)
目标:
我们希望提取出 video 的 URL。如果标签带有参数(如宽高),我们也可能需要捕获它们,以便后续处理。
设计正则表达式:
我们将分步构建正则表达式,使其更具可读性和可维护性。
1. 匹配 [video] 标签的开始:
* \[video : 匹配字面上的 [video。 [ 是正则表达式的特殊字符,所以需要用 \ 转义。
2. 匹配可选的参数:
* (=[^\]]*)? : 这是一个可选的捕获组((...)),表示 ] 之前可能出现的任何非 ] 字符。
* = : 匹配字面上的 =。
* [^\]]* : 匹配零个或多个(*)不是 ] 的字符([^\]])。这可以捕获 width:height 或 url 或 width:height:url 等。
* ? : 使整个参数部分成为可选的。
3. 匹配 ] 标签结束:
* \] : 匹配字面上的 ]。 ] 也是特殊字符,需要转义。
4. 匹配 video URL:
* ([^\[]*) : 这是一个捕获组,用来捕获 URL。
* [^\[]* : 匹配零个或多个(*)不是 [ 的字符。我们假设 URL 不会包含 [。
* 注意: 这是一个简化的 URL 匹配。如果需要更严格的 URL 验证,可以使用更复杂的模式,但对于 UBB 解析来说,这种模式通常足够。
5. 匹配 [/video] 标签的结束:
* \[/video\] : 匹配字面上的 [/video]。
整合后的正则表达式:regex
\[video(?:=([^\]]*))?\]([^\[]*)\[\/video\]
解释:
* \[video : 匹配 [video
* (?:=([^\]]*))? :
* (?: ... )? : 这是一个非捕获组(?:),它让整个参数部分成为可选的,但不会额外创建一个捕获组。
* = : 匹配 =。
* ([^\]]*) : 这是第一个捕获组,捕获参数部分(例如 width:height 或 url)。
* \] : 匹配 ]
* ([^\[]*) : 这是第二个捕获组,捕获 video 的 URL。
* \[\/video\] : 匹配 [/video]
Golang 实现:go
package main
import (
"fmt"
"regexp"
)
// VideoInfo 结构体用于存储解析出的视频信息
type VideoInfo struct {
URL string
Params string // 例如 "width:height" 或 "url"
}
func main() {
ubbText := `
这是一个包含视频的文本。
<video src="http://example.com/videos/intro.mp4" style="max-width:500px;min-width:320px;height:auto;display:block;margin:0 auto;" controls></video>
这是一个带有宽高的视频。
<video src="http://example.com/videos/tutorial.mov" 640:480></video>
这是一个只带URL参数的视频 (不太常见)。
<video src="http://example.com/videos/promo.avi" http://example.com/videos/promo.avi></video>
这是一个混合参数的视频。
<video src="http://example.com/videos/hd.mp4" 1280:720:http://example.com/videos/hd.mp4></video>
这是一个没有视频标签的普通文本。
这是一个其他标签:<strong>粗体</strong>
`
// 编译正则表达式
// [video(?:=([^\]]*))?] 匹配 [video] 或 [video=参数]
// (?:=([^\]]*))? - 可选的非捕获组,匹配 '=' 后面直到 ']' 的内容(捕获到第一个捕获组)
// [^\[]* - 捕获 URL(第二个捕获组)
// \[\/video\] - 匹配 [/video]
videoRegex := regexp.MustCompile(`\[video(?:=([^\]]*))?\]([^\[]*)\[\/video\]`)
matches := videoRegex.FindAllStringSubmatch(ubbText, -1)
fmt.Println("解析到的视频信息:")
if len(matches) == 0 {
fmt.Println("未找到任何视频标签。")
} else {
for _, match := range matches {
// match[0] 是整个匹配到的字符串 (例如 "<video src="http://example.com/videos/tutorial.mov" 640:480></video>")
// match[1] 是第一个捕获组的内容 (例如 "640:480" 或 "" 如果没有参数)
// match[2] 是第二个捕获组的内容 (URL)
var videoInfo VideoInfo
videoInfo.URL = match[2]
videoInfo.Params = match[1] // 这个可能为空字符串
fmt.Printf(" - 完整标签: %s\n", match[0])
fmt.Printf(" URL: %s\n", videoInfo.URL)
if videoInfo.Params != "" {
fmt.Printf(" 参数: %s\n", videoInfo.Params)
}
}
}
}
输出示例:
解析到的视频信息:
- 完整标签: <video src="http://example.com/videos/intro.mp4" style="max-width:500px;min-width:320px;height:auto;display:block;margin:0 auto;" controls></video>
URL: http://example.com/videos/intro.mp4
- 完整标签: <video src="http://example.com/videos/tutorial.mov" 640:480></video>
URL: http://example.com/videos/tutorial.mov
参数: 640:480
- 完整标签: <video src="http://example.com/videos/promo.avi" http://example.com/videos/promo.avi></video>
URL: http://example.com/videos/promo.avi
参数: http://example.com/videos/promo.avi
- 完整标签: <video src="http://example.com/videos/hd.mp4" 1280:720:http://example.com/videos/hd.mp4></video>
URL: http://example.com/videos/hd.mp4
参数: 1280:720:http://example.com/videos/hd.mp4
关于 “完美” 的说明:
* URL 的精确匹配: 上面的正则表达式 [^\[]* 仅仅是匹配直到下一个 [ 之前的所有字符。这在大多数情况下是足够的,但如果 URL 本身可能包含 [ 或 ](尽管非常罕见),这个正则表达式就会出错。一个更精确的 URL 匹配会非常复杂,通常不需要在 UBB 解析中做到如此极致,除非有特殊需求。
* 参数的解析: 正则表达式捕获了参数部分 match[1]。如果参数格式是 width:height,你可以进一步使用 strings.Split 来解析它。但如果参数格式变得非常复杂,可能需要更复杂的正则表达式或专门的解析逻辑。
* 嵌套标签: 这个正则表达式 不能 正确处理嵌套的 [video] 标签。UBB 的设计通常不支持标签的深度嵌套。
* 其他 UBB 标签的干扰: 如果 UBB 文本中存在其他类似 [video] 的标签,但内容不匹配,regexp 会忽略它们。
如何使用 regexp 达到最佳效果:
1. regexp.Compile 或 regexp.MustCompile: 编译正则表达式可以提高性能,特别是当你在循环中多次使用同一个正则表达式时。MustCompile 在编译失败时会 panic,适合在程序启动时使用,确保正则表达式是有效的。
2. FindAllStringSubmatch(str, -1): 这个函数会查找字符串 str 中所有不重叠的匹配项,并返回一个 [][]string 类型的切片。
* -1 表示查找所有匹配项。
* 内层切片 []string 的第一个元素 ([0]) 是整个匹配到的字符串。
* 随后的元素 ([1], [2], …) 是正则表达式中定义的捕获组的内容。
3. 错误处理: 对于 FindAllStringSubmatch,如果没有任何匹配项,它会返回 nil。所以需要检查切片是否为空。
进阶解析参数:
如果 match[1](参数部分)不为空,你可以根据预期的格式来解析它:go
import (
"strings"
// ... other imports
)
// ... inside the loop ...
videoInfo.URL = match[2]
paramStr := match[1]
if paramStr != "" {
videoInfo.Params = paramStr
// 假设参数是 "width:height"
parts := strings.Split(paramStr, ":")
if len(parts) == 2 {
// 尝试解析 width 和 height
// width, errW := strconv.Atoi(parts[0])
// height, errH := strconv.Atoi(parts[1])
// ... do something with width and height
}
// 可以根据实际情况添加更多参数解析逻辑
}
// ...
通过这种方式,你可以使用 Golang 的 regexp 包有效地解析 UBB 代码中的 video 播放标签,并从中提取出关键信息。