ruby heredoc 和 sprintf 转义 %:抛出格式错误的字符串 %"(ArgumentError)

ruby heredoc and sprintf escape %: throwing malformed format sting %" (ArgumentError)

我正试图在 ruby heredoc 中转义 %

property_str =<<~HEREDOC.strip
    function string get_type_name();
        return $sformatf("%%");
    endfunction: get_type_name

    property signal_x(ctrl_signal);
        @(posedge %{clock}) disable iff(%{reset} || $isunknown(%{reset}) || assertion_disable)
        (~$isunknown(ctrl_signal));
    endproperty: signal_x
HEREDOC

那我试着打印一下

create_assertions.push(sprintf(property_str % {:clock => %Q(my_clk), :reset => %Q(my_rst)}))

如您所见,我已经对 %%% 进行了两次转义,但我仍然不断得到:

script.rb:518:in `sprintf': malformed format string - %" (ArgumentError)

谁能指出我可能哪里出错了?

您的问题是 String#% and Kernel#sprintf 都在解释字符串中的 %。这个:

create_assertions.push(sprintf(property_str % {:clock => %Q(my_clk), :reset => %Q(my_rst)}))

等同于:

fmt = property_str % {:clock => %Q(my_clk), :reset => %Q(my_rst)}
create_assertions.push(sprintf(fmt))

fmt 将如下所示:

function string get_type_name();
    return $sformatf("%");
endfunction: get_type_name

property signal_x(ctrl_signal);
    @(posedge my_clk) disable iff(my_rst || $isunknown(my_rst) || assertion_disable)
    (~$isunknown(ctrl_signal));
endproperty: signal_x

注意字符串第二行的 return $sformatf("%");String#% 会将原始 %% 转换为单个 %

然后您将该字符串放入 Kernel#sprintf,它会尝试将 %" 解释为转义序列并报错。

要么仅使用 property_str % {:clock => %Q(my_clk), :reset => %Q(my_rst)} 构建您的字符串,要么,如果您确实必须使用两种格式化方法,请将 property_str 中的 % 加倍,以便 sprintf将看到 %% 并将其变成单个 %:

property_str =<<~HEREDOC.strip
    function string get_type_name();
        return $sformatf("%%%%");
    ...
HEREDOC