Can we get the slots in the format string?

I am interested in getting a list of slots in a string related to operator formatting %. If I have a method slotsfor this, it will do the following:

t = '... %{s1} ... %{s2} ... %{s3} ...'
t.slots # => ['s1', 's2', 's3']
  • Is there a method such as hypothetical slots?
  • Is there any way to get these slots WITHOUT using a regular expression , but using the same parsing procedure as the Rubin engine?
  • Is there a library that implements something like format interpolation that provides a method similar to the one indicated slots?
  • If there is no other option, how can I create a descent parser (not a regular expression) for this case?

I am reading what I think is the source code% , and I'm afraid that line formatting does not have an obvious separation for detection slots.

+4
source share
3 answers

At least you can do this:

t = '... %{s1} ... %{s2} ... %{s3} ...'

h = {}
begin
  t % h
rescue KeyError => e
  h[e.key] = true
  retry
end
h.keys # => [:s1, :s2, :s3]
+1
source

THIS DOES NOT ANSWER THE QUESTION! This handles cases like"#{a}" See My other answer for what OP asked.


The code you are reading is not actually related to Ruby interpolation processing. This is the code for the family of functions sprintf, as indicated in the file name. You can notice this easily: caseit is not looking '#'and instead deals with {both and with <(whereas you cannot interpolate with #<>).

scary parse.y, tokadd_string.

, ...

#, STR_FUNC_EXPAND (STR_FUNC_EXPAND - ), @, { $ while > , # . (@{$ , , )

tokadd_string, parse_string. #, STR_FUNC_EXPAND, , parser_peek_variable_name ( , #$a, #@a).

case '{' , : tSTRING_DBEG, . command_start, ; .

, , . "" ruby, ..

, : , , . #$ #@, .

0

, rb_sym_intern.

, (.. '%{a} % {}), , Hash .

, rb_check_symbol_cstr, Ruby.

If you want to intercept only the values ​​that exist in Hash, you can add your code to another after nextvalue == Qundef.

Please note: this will require interpolation.

If you want to do this without requiring interpolation ...

An ugly parser made on the fly for this:

str = '%% %{a} %%{b} %%%{c} %%%%{d}'
is_escaped = false
list = []
i = 0
while i < str.length
  c = str[i]
  if is_escaped
    is_escaped = false
  elsif c == '%'
    is_escaped = true
  elsif c == '{'
    pos = str.index('}', i + 1) # start scanning from i
    if pos == nil
      puts "unmatched %{ in string"
      break
    end
    list.push(str.slice(i + 1, pos - i - 1))
    i = pos
  end
  i += 1
end
puts list
0
source

Source: https://habr.com/ru/post/1694192/


All Articles