如何用regex和Golang替换可选组

时间:2017-04-02 12:29:55

标签: regex go

我想翻译一下:

{% img <right> /images/testing %}

进入这个:

{{< figure <class="right"> src="/images/testing" >}}

在Golang中使用正则表达式。源字符串中<>中的部分是可选的。

我有这个代码,当主要测试用例存在时,第一个捕获组存在(&#34; 正确&#34;):

regexp.MustCompile(`{%\s*img\s*(\p{L}*)\s+([/\S]+)\s+%}`)
.ReplaceAllString("{% img right /images/testing %}", "{{< figure class=\"$1\" src=\"$2\" >}}")

如果缺少可选组,我会得到:

{{< figure class="" src="/images/testing" >}}

这不是我需要的 - 我希望整个class=""部分不见了,就像这样:

{{< figure src="/images/testing" >}}

这可能吗?我可以在替换字符串中以某种方式表示:

{{< figure class=\"$1\" src=\"$2\" >}}

如果可选组为空,我希望其他文字(&#34; class = &#34;)消失了吗?

1 个答案:

答案 0 :(得分:0)

Go regexp不支持条件语句,Replace系列regexp函数也不支持。 解决方法取决于您拥有的特殊情况的数量。

如果您只有一个案例,我建议您只进行两次更换:首先用属性集替换所有出现的事件,然后替换没有属性(on play)的所有案例:

txt := `{% img right /images/testing %}\n{% img /images/testing %}`

// without attribute
txt = regexp.MustCompile(`{%\s*img\s*([/\S]+)\s+%}`).
  ReplaceAllString(txt, "{{< figure src=\"$1\" >}}")

// with attribute
txt = regexp.MustCompile(`{%\s*img\s*(\p{L}*)\s+([/\S]+)\s+%}`).
  ReplaceAllString(txt, "{{< figure class=\"$1\" src=\"$2\" >}}")

如果你说这是效率低下我说:可能,是的。如果你想要更高效的东西(即不会两次迭代源字符串的东西),那么你必须构建更类似于解析器的东西,解析器在检测时决定使用哪种格式。粗略的草图就是这样的(on play):

src := []byte("ok" + "{% img right /images/testing %}" + "this" + 
              "{% img /images/testing %}" + "no?")
dst := bytes.NewBufferString("")
cidx := 0

for _, match := range p.FindAllSubmatchIndex(src, -1) {
    dst.Write(src[cidx:match[0]])
    dst.WriteString(newFormat(src, src[match[2]:match[3]], src[match[4]:match[5]]))
    cidx = match[1]
}
dst.Write(src[cidx:])

在此示例中,您将源文本src中的所有内容复制到缓冲区dst,将模式的每个匹配项替换为函数值的输出。然后,此功能可以决定是否包含特定格式。