宏和字符串插值 (Julia)
Macros and string interpolation (Julia)
假设我制作了这个简单的字符串宏
macro e_str(s)
return string("I touched this: ",s)
end
如果我将它应用于带插值的字符串,我
获得:
julia> e"foobar $(log(2))"
"I touched this: foobar $(log(2))"
而我想获得:
julia> e"foobar $(log(2))"
"I touched this: foobar 0.6931471805599453"
我必须对宏声明进行哪些更改?
在编译时解析字符串比委托给 Julia 更好。基本上,将字符串放入 IOBuffer
中,扫描字符串中的 $
符号,并在它们出现时使用 parse
函数。
macro e_str(s)
components = []
buf = IOBuffer(s)
while !eof(buf)
push!(components, rstrip(readuntil(buf, '$'), '$'))
if !eof(buf)
push!(components, parse(buf; greedy=false))
end
end
quote
string($(map(esc, components)...))
end
end
这不适用于转义的 $
字符,但可以通过一些小的更改来解决 \
的问题。我在 post.
的底部包含了一个基本示例
我这样写是因为字符串宏通常不用于模拟 Julia 字符串——具有常规字符串文字的常规宏更适合该目的。所以自己编写解析并没有那么糟糕,尤其是因为它允许自定义扩展。如果您真的希望解析与 Julia 解析它的方式相同,您可以转义字符串然后重新解析它,正如@MattB 建议的那样:
macro e_str(s)
esc(parse("\"$(escape_string(s))\""))
end
生成的表达式是一个 :string
表达式,您可以将其转储和检查,然后以通常的方式进行分析。
字符串宏没有内置插值功能。但是,可以手动实现此功能。请注意,如果不转义与周围字符串宏具有相同定界符的字符串文字,则无法嵌入;也就是说,虽然 """ $("x") """
是可能的,但 " $("x") "
是不可能的。相反,这必须转义为 " $(\"x\") "
.
手动实现插值有两种方法:手动实现解析,或让 Julia 进行解析。第一种方法更灵活,但第二种方法更容易。
手动解析
macro interp_str(s)
components = []
buf = IOBuffer(s)
while !eof(buf)
push!(components, rstrip(readuntil(buf, '$'), '$'))
if !eof(buf)
push!(components, parse(buf; greedy=false))
end
end
quote
string($(map(esc, components)...))
end
end
Julia 解析
macro e_str(s)
esc(parse("\"$(escape_string(s))\""))
end
此方法对字符串进行转义(但请注意 escape_string
不会 对 $
符号进行转义)并将其传回 Julia 的解析器进行解析。转义字符串是必要的,以确保 "
和 \
不影响字符串的解析。生成的表达式是一个 :string
表达式,可以对其进行检查和分解以用于宏目的。
假设我制作了这个简单的字符串宏
macro e_str(s)
return string("I touched this: ",s)
end
如果我将它应用于带插值的字符串,我 获得:
julia> e"foobar $(log(2))"
"I touched this: foobar $(log(2))"
而我想获得:
julia> e"foobar $(log(2))"
"I touched this: foobar 0.6931471805599453"
我必须对宏声明进行哪些更改?
在编译时解析字符串比委托给 Julia 更好。基本上,将字符串放入 IOBuffer
中,扫描字符串中的 $
符号,并在它们出现时使用 parse
函数。
macro e_str(s)
components = []
buf = IOBuffer(s)
while !eof(buf)
push!(components, rstrip(readuntil(buf, '$'), '$'))
if !eof(buf)
push!(components, parse(buf; greedy=false))
end
end
quote
string($(map(esc, components)...))
end
end
这不适用于转义的 $
字符,但可以通过一些小的更改来解决 \
的问题。我在 post.
我这样写是因为字符串宏通常不用于模拟 Julia 字符串——具有常规字符串文字的常规宏更适合该目的。所以自己编写解析并没有那么糟糕,尤其是因为它允许自定义扩展。如果您真的希望解析与 Julia 解析它的方式相同,您可以转义字符串然后重新解析它,正如@MattB 建议的那样:
macro e_str(s)
esc(parse("\"$(escape_string(s))\""))
end
生成的表达式是一个 :string
表达式,您可以将其转储和检查,然后以通常的方式进行分析。
字符串宏没有内置插值功能。但是,可以手动实现此功能。请注意,如果不转义与周围字符串宏具有相同定界符的字符串文字,则无法嵌入;也就是说,虽然 """ $("x") """
是可能的,但 " $("x") "
是不可能的。相反,这必须转义为 " $(\"x\") "
.
手动实现插值有两种方法:手动实现解析,或让 Julia 进行解析。第一种方法更灵活,但第二种方法更容易。
手动解析
macro interp_str(s)
components = []
buf = IOBuffer(s)
while !eof(buf)
push!(components, rstrip(readuntil(buf, '$'), '$'))
if !eof(buf)
push!(components, parse(buf; greedy=false))
end
end
quote
string($(map(esc, components)...))
end
end
Julia 解析
macro e_str(s)
esc(parse("\"$(escape_string(s))\""))
end
此方法对字符串进行转义(但请注意 escape_string
不会 对 $
符号进行转义)并将其传回 Julia 的解析器进行解析。转义字符串是必要的,以确保 "
和 \
不影响字符串的解析。生成的表达式是一个 :string
表达式,可以对其进行检查和分解以用于宏目的。