ruby参数化正则表达式

时间:2010-05-07 14:35:06

标签: ruby regex string

我有一个字符串,如“{some | words | are | here}”或“{another | set | of | words}”

所以一般来说,字符串由一个开口的花括号,一个由管道分隔的单词和一个右大括号组成。

获取该字符串中所选单词的最有效方法是什么?

我想做这样的事情:

@my_string = "{this|is|a|test|case}"
@my_string.get_column(0) # => "this"
@my_string.get_column(2) # => "is"
@my_string.get_column(4) # => "case"

get_column方法应该包含什么?

1 个答案:

答案 0 :(得分:2)

所以这就是我现在喜欢的解决方案:

class String
  def get_column(n)
    self =~ /\A\{(?:\w*\|){#{n}}(\w*)(?:\|\w*)*\}\Z/ && $1
  end
end

我们使用正则表达式来确保字符串的格式正确,同时抓取正确的列。

正则表达式的解释:

  • \A是字符串的开头,\Z是结尾,所以此正则表达式与enitre字符串匹配。
  • 由于花括号具有特殊含义,我们将其作为\{\}进行转义,以匹配字符串开头和结尾的花括号。
  • 接下来,我们想跳过前n列 - 我们不关心它们。
    • 前一列是一些字母后跟一个竖线,因此我们使用标准\w来匹配类似字的字符(包括数字和下划线,但为什么不是)和*匹配任意数量的。垂直条具有特殊含义,因此我们必须将其作为\|进行转义。由于我们要对此进行分组,因此我们将其全部包含在非捕获的parens (?:\w*\|)中(?:使其无法捕获)。
    • 现在我们有n之前的列,所以我们告诉正则表达式使用count regex匹配列模式n次 - 只需在模式后面的花括号中加一个数字。我们使用标准字符串替换,因此我们只需将{#{n}}表示“与前一个模式完全匹配n次。
  • 之后的第一个非跳过的列就是我们关心的那个,所以我们把它放在捕获parens中:(\w*)
  • 然后我们跳过剩下的列,如果存在的话:(?:\|\w*)*

捕获列会将其放入$1,因此如果正则表达式匹配,我们会返回该值。如果没有,我们返回nil,因为这个String没有n列。

一般情况下,如果您希望列中不只有单词(例如"{a phrase or two|don't forget about punctuation!|maybe some longer strings that have\na newline or two?}"),那么只需将正则表达式中的所有\w替换为[^|{}],这样您就可以拥有每列包含除花括号或竖条之外的任何内容。


这是我以前的解决方案

class String
  def get_column(n)
    raise "not a column string" unless self =~ /\A\{\w*(?:\|\w*)*\}\Z/
    self[1 .. -2].split('|')[n]
  end
end

我们使用类似的正则表达式来确保String包含一组列或引发错误。然后我们从正面和背面剥离花括号(使用self[1 .. -2]限制从第一个字符开始到倒数第二个字符结束的子字符串),使用管道字符分割列(使用{{1}创建一个列数组),然后找到第n列(使用标准数组查找.split('|'))。

我想,只要我使用正则表达式验证字符串,我不妨用它来捕获列。