如何在Ruby中使用格式化掩码从字符串中提取值

如何在Ruby中使用格式化掩码从字符串中提取值,ruby,Ruby,我们可以在Ruby中实现:“我有%{amount}%{food}”%{amount:5,food:'apples'}得到“我有5个苹果”。有没有常见的反变换方法:使用“我有5个苹果”和“我有%{amount}%{food}”得到{amount:5,food:'apples'} def doit(s1, s2) a1 = s1.split a2 = s2.split a2.each_index.with_object({}) do |i,h| word = a2[i][/(?

我们可以在Ruby中实现:
“我有%{amount}%{food}”%{amount:5,food:'apples'}
得到“我有5个苹果”。有没有常见的反变换方法:使用“我有5个苹果”和“我有%{amount}%{food}”得到
{amount:5,food:'apples'}

def doit(s1, s2)
  a1 = s1.split 
  a2 = s2.split
  a2.each_index.with_object({}) do |i,h|
    word = a2[i][/(?<=%\{).+(?=\})/]
    h[word.to_sym] = a1[i] unless word.nil?
  end.transform_values { |s| s.match?(/\A\-?\d+\z/) ? s.to_i : s }
end

正则表达式的内容是,“匹配一个或多个字符(
+
),前面紧跟着
“%{”
(?)如果子字符串用空格分隔,则可以找到相应的正则表达式:

text=“我有5个苹果”
#“我有%{amount}%{food}”
格式=/\AI有(?\S+(\S+)\z/
p text.match(格式).named_捕获
#{“数量”=>“5”,“食物”=>“苹果”}

您没有显示任何代码,因此我将把它作为一个练习,将
“I have%{amount}%{food}”字符串转换为
/\AI have(?\S+)(\S+)\z/
正则表达式。

这叫做正则表达式。@DaveNewton,有没有办法使用%{}使用正则表达式的语法?我不知道,尽管您可以使用(相对简单的)进行命名捕获并转换为命名捕获正则表达式模板化字符串不应该太难…但可能不值得。您试图解决的最终问题是什么?我解析HTML并希望在配置中包含一些字符串,这些字符串既可以用于在页面中搜索字符串,也可以从找到的字符串中提取变量值。类似于
http://some.site/event/%{id}
。我可以使用
CONFIG[:event_link]{id:'}
在页面上搜索事件,但不知道如何使用它来提取找到的事件的id。您需要查找的所有内容都是相同的吗?还是任意的?没有“返回”“据我所知,在大多数/所有字符串模板系统中,尽管有些系统可能会提供模板的AST,这会使自动创建相应的regex.IIRC变得(有些)更容易。也有一些系统允许您提供示例输入并创建“解析器”但是我不知道我脑子里有什么。非常感谢!这不是我寻找的一种“普通方式”,但它确实起到了作用,对于类似的情况可能非常有用。不过有一个解决办法:最后一个将字符串转换成整数的正则表达式应该是:
/\a\-?\d+\z/
Michael,减号只需转义即可在字符类中,以避免将其解释为表示范围。例如,
'-'.match?/[a-z]/[a-z]/\35;=>false
'-'.match?/[a-z]/\35;=>true
。此外,如果减号出现在字符类的开头或结尾,则无需转义,因为它显然不会表示范围:
'-'.match?/[-ab]/#=>true
'-'.匹配?/[ab-]/#=true
。好的,谢谢你的解释。但是我在d之前添加了反斜杠,而不是在减号之前。因此,正确的regexp应该是
/\a-?\d+\z/
,对吗?没错。我不知道
d
之前的反斜杠发生了什么事。很明显,当我执行该方法时,它就在那里。谢谢你的提示。你的第二条评论有反斜杠在减号之前,这也吸引了我的眼球。
s1 = "I have 5 apples"
s2 = "I have %{amount} %{food}"
doit(s1, s2)
  #=> {:amount=>5, :food=>"apples"} 

s1 = "223 parcels were delivered last month"
s2 = "%{number} parcels were %{action} last %{period}"
doit(s1, s2)
  #=> {:number=>223, :action=>"delivered", :period=>"month"}
text = "I have 5 apples"
# "I have %{amount} %{food}"
format = /\AI have (?<amount>\S+) (?<food>\S+)\z/

p text.match(format).named_captures
# {"amount"=>"5", "food"=>"apples"}