2014-01-08 44 views
6

在Perl中,我使用以下一行语句通过正则表达式将匹配从字符串中拉出并分配给它们。此人们发现一个匹配,并将其分配到一个字符串:红宝石单线捕捉正则表达式匹配

my $string = "the quick brown fox jumps over the lazy dog."; 

my $extractString = ($string =~ m{fox (.*?) dog})[0]; 

结果:$extractString == 'jumps over the lazy'

而这一次创建从多个匹配的数组:

my $string = "the quick brown fox jumps over the lazy dog."; 

my @extractArray = $string =~ m{the (.*?) fox .*?the (.*?) dog}; 

结果:@extractArray == ['quick brown', 'lazy']

是否有一种等同的方式来在Ruby中创建这些单行内容?

回答

5
string = "the quick brown fox jumps over the lazy dog." 

extract_string = string[/fox (.*?) dog/, 1] 
# => "jumps over the lazy" 

extract_array = string.scan(/the (.*?) fox .*?the (.*?) dog/).first 
# => ["quick brown", "lazy"] 

这种方法也将返回(而不是抛出一个错误)nil如果没有找到匹配。

extract_string = string[/MISSING_CAT (.*?) dog/, 1] 
# => nil 

extract_array = string.scan(/the (.*?) MISSING_CAT .*?the (.*?) dog/).first 
# => nil 
7

使用String#matchMatchData#[]或来获得匹配的反向引用。

s = "the quick brown fox jumps over the lazy dog." 

s.match(/fox (.*?) dog/)[1] 
# => "jumps over the lazy" 
s.match(/fox (.*?) dog/).captures 
# => ["jumps over the lazy"] 

s.match(/the (.*?) fox .*?the (.*?) dog/)[1..2] 
# => ["quick brown", "lazy"] 
s.match(/the (.*?) fox .*?the (.*?) dog/).captures 
# => ["quick brown", "lazy"] 

UPDATE

为了避免undefined method []错误:

(s.match(/fox (.*?) cat/) || [])[1] 
# => nil 
(s.match(/the (.*?) fox .*?the (.*?) cat/) || [])[1..2] 
# => nil 
(s.match(/the (.*?) fox .*?the (.*?) cat/) || [])[1..-1] # instead of .captures 
# => nil 
+0

发现s.match(/ fox(。*?)dog /)[1]'方法存在问题。如果找不到匹配项,Ruby 2.1会抛出一个“未定义的方法'[]”错误。例如,将其更改为's.match(/ fox(。*?)cat /)[1]',它会窒息。 –

+0

@ AlanW.Smith,我更新了答案。 '(s.match(/ fox(。*?)cat /)|| [])[1]' – falsetru

2

首先,在Ruby中编写时要小心用Perl语言思考。为了使代码更具可读性,我们做了一些更加细致的事情。

我会写my @extractArray = $string =~ m{the (.*?) fox .*?the (.*?) dog};为:

string = "the quick brown fox jumps over the lazy dog." 

string[/the (.*?) fox .*?the (.*?) dog/] 
extract_array = $1, $2 
# => ["quick brown", "lazy"] 

红宝石,如Perl,意识到了capture groups的,并将其分配给值$1$2等。这些敛值时,使得它非常干净,清晰并在稍后分配它们。正则表达式引擎允许您创建和分配命名捕获,但它们往往会掩盖发生的事情,所以为了清楚起见,我倾向于这样。

我们可以使用match到那里太:

/the (.*?) fox .*?the (.*?) dog/.match(string) # => #<MatchData "the quick brown fox jumps over the lazy dog" 1:"quick brown" 2:"lazy"> 

,但最终的结果更具可读性?

extract_array = /the (.*?) fox .*?the (.*?) dog/.match(string)[1..-1] 
# => ["quick brown", "lazy"] 

命名捕获有趣太:

/the (?<quick_brown>.*?) fox .*?the (?<lazy>.*?) dog/ =~ string 
quick_brown # => "quick brown" 
lazy # => "lazy" 

却致使想知道这些变量初始化和分配; I肯定不会在正则表达式中看到这些发生,所以它可能会让其他人感到困惑,并再次成为维护问题。


卡里说:

To elaborate a little on named captures, if match_data = string.match /the (?.?) fox .?the (?.*?) dog/, then match_data[:quick_brown] # => "quick brown" and match_data[:lazy] # => "lazy" (as well as quick_brown # => "quick brown" and lazy # => "lazy"). With named captures available, I see no reason for using global variables or Regexp.last_match, etc.

是的,但有一些气味也有。

我们可以用values_atmatch的MatchData结果来获取捕获的值,但也有在课堂上的一些直观的行为,把我关:

/the (?<quick_brown>.*?) fox .*?the (?<lazy>.*?) dog/.match(string)['lazy'] 

作品,并暗示MatchData知道如何像一个哈希:

{'lazy' => 'dog'}['lazy'] # => "dog" 

,它有一个values_at方法,像哈希,但它并没有直观地工作:

/the (?<quick_brown>.*?) fox .*?the (?<lazy>.*?) dog/.match(string).values_at('lazy') # => 
# ~> -:6:in `values_at': no implicit conversion of String into Integer (TypeError) 

鉴于:

/the (?<quick_brown>.*?) fox .*?the (?<lazy>.*?) dog/.match(string).values_at(2) # => ["lazy"] 

现在就像一个数组:

['all captures', 'quick brown', 'lazy'].values_at(2) # => ["lazy"] 

我想一致性,这使我的头不疼。

+1

我认为将匹配结果保留在全局变量中并不干净。这只是Perl的糟糕传统。如果你可以做没有全局变量的事情,那么这是可取的。我个人有一个经验,当我尝试访问全局匹配变量时,我有正则表达式在嵌套代码匹配,这是一团糟。 – sawa

+1

无论如何,那些“全局变量”是存在的,它们不是因为它们被用于赋值而发生的。而且,是的,它们是Perlism,但是更有用的一个。它们被任何随后的正则表达式使用所覆盖,包括被调用的例程,因此重要的是要记住它们是不稳定的;立即抓住它们,不要指望它们在其他地方可用。 –

+0

我知道他们在那里。但你可以忽略它们。你无法避免它们的存在,但你可以忘记它们,这会使代码变得更清晰。 – sawa