You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Participle解析遇Unexpected Token错误及结果为空问题

使用Participle解析.htaccess时遇到的Unexpected Token及解析结果为空问题

问题背景

我在学习用Participle解析.htaccess规则时,碰到了Unexpected Token错误,无法定位原因。原代码如下:

// nolint: golint, dupl
package main

import (
    "fmt"
    "io"

    "github.com/alecthomas/participle/v2"
    "github.com/alecthomas/participle/v2/lexer"
)

var htaccessLexer = lexer.MustSimple([]lexer.SimpleRule{
    {"Comment", `^#[^\n]*`},
    {"Ident", `^\w+`},
    {"Int", `\d+`},
    {"String", `("(\\"|[^"])*"|\S+)`},
    {"EOL", `[\n\r]+`},
    {"whitespace", `[ \t]+`},
})

type HTACCESS struct {
    Directives []*Directive `@@*`
}

type Directive struct {
    Pos lexer.Position

    ErrorDocument *ErrorDocument `@@`
}

type ErrorDocument struct {
    Code int    `"ErrorDocument" @Int`
    Path string `@String`
}

var htaccessParser = participle.MustBuild[HTACCESS](
    participle.Lexer(htaccessLexer),
    participle.CaseInsensitive("Ident"),
    participle.Unquote("String"),
    participle.Elide("whitespace"),
)

func Parse(r io.Reader) (*HTACCESS, error) {
    program, err := htaccessParser.Parse("", r)
    if err != nil {
        return nil, err
    }

    return program, nil
}

func main() {
    v, err := htaccessParser.ParseString("", `ErrorDocument 403 test`)

    if err != nil {
        panic(err)
    }

    fmt.Println(v)
}

我认为代码逻辑没问题,预期能识别到403,但实际无法解析。

编辑补充

后来我修改了Lexer规则,代码如下:

var htaccessLexer = lexer.MustSimple([]lexer.SimpleRule{
    {"dir", `^\w+`},
    {"int", `\d+`},
    {"str", `("(\\"|[^"])*"|\S+)`},
    {"EOL", `[\n\r]+`},
    {"whitespace", `\s+`},
})

修改后Unexpected Token错误消失,但解析结果仍为空数组,我不清楚修改Lexer规则解决原错误的原因,也不知道解析为空的问题出在哪。


问题原因分析

1. 原Lexer导致Unexpected Token的原因

  • 行首锚点^误用:Participle的SimpleLexer是逐字符扫描匹配的,不是按行处理。原规则里Comment和Ident的^会强制要求匹配行首位置,当扫描到非行首的字符时,这些规则会匹配失败,后续规则无法正常触发,最终抛出Unexpected Token错误。
  • 空白规则范围不足:原whitespace仅匹配[ \t]+,未覆盖所有空白类型,但核心问题还是锚点的误用。

2. 修改Lexer后解析结果为空的原因

修改后的Lexer把规则名改成了dir、int、str,但结构体标签里依然使用@Int、@String来指定token类型。Participle是通过规则名称来匹配token的,两者名称不对应,导致解析器无法识别对应token,最终返回空数组。

解决方案

  1. 修复原Lexer的锚点问题:去掉规则中的^,让SimpleLexer从当前扫描位置正常匹配:
var htaccessLexer = lexer.MustSimple([]lexer.SimpleRule{
    {"Comment", `#[^\n]*`},
    {"Ident", `\w+`},
    {"Int", `\d+`},
    {"String", `("(\\"|[^"])*"|\S+)`},
    {"EOL", `[\n\r]+`},
    {"whitespace", `[ \t]+`},
})
  1. 保持规则名与结构体标签一致:如果要修改规则名,需同步修改结构体中的标签(比如把@Int改成@int),或者直接保留原规则名Ident、Int、String。

修正后的代码运行后,就能正确解析出ErrorDocument的Code和Path。

内容的提问来源于stack exchange,提问作者Krum110487

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 09:30:57