Как разобрать подстроку между последним набором скобок в строке в ruby - PullRequest
1 голос
/ 28 марта 2009

В моем приложении ruby ​​on rails я пытаюсь создать парсер для извлечения метаданных из строки.

Допустим, пример строки:

Быстрая рыжая лиса (откровенно 10) прыгнула над ленивой коричневой собакой (Ральф, 20).

Я хочу извлечь подстроку из последнего вхождения ().

Итак, я хочу получить «ralph, 20» независимо от того, сколько () в строке.

Есть ли лучший способ создать это извлечение строки ruby ​​... regexp?

Спасибо

John

Ответы [ 3 ]

2 голосов
/ 28 марта 2009

Похоже, вы хотите sexeger . Они работают, переворачивая строку, выполняя обратное регулярное выражение со строкой, а затем переворачивая результаты. Вот пример (простите за код, я действительно не знаю Ruby):

#!/usr/bin/ruby

s = "The quick red fox (frank,10) jumped over the lazy brown dog (ralph, 20).";

reversed_s = s.reverse;
reversed_s =~ /^.*?\)(.*?)\(/;
result = $1.reverse;
puts result;

Тот факт, что это не набирает голоса, говорит мне, что никто не нажал, чтобы прочитать, почему вы хотите использовать sexeger, поэтому вот результаты теста:

do they all return the same thing?
ralph, 20
ralph, 20
ralph, 20
ralph, 20
                        user     system      total        real
scan greedy         0.760000   0.000000   0.760000 (  0.772793)
scan non greedy     0.750000   0.010000   0.760000 (  0.760855)
right index         0.760000   0.000000   0.760000 (  0.770573)
sexeger non greedy  0.400000   0.000000   0.400000 (  0.408110)

А вот и эталон:

#!/usr/bin/ruby

require 'benchmark'

def scan_greedy(s)
    result = s.scan(/\([^)]*\)/x)[-1]
    result[1 .. result.length - 2]
end

def scan_non_greedy(s)
    result = s.scan(/\(.*?\)/)[-1]
    result[1 .. result.length - 2]
end

def right_index(s)
    s[s.rindex('(') + 1 .. s.rindex(')') -1]
end

def sexeger_non_greedy(s)
    s.reverse =~ /^.*?\)(.*?)\(/
    $1.reverse
end

s = "The quick red fox (frank,10) jumped over the lazy brown dog (ralph, 20).";

puts "do they all return the same thing?", 
    scan_greedy(s), scan_non_greedy(s), right_index(s), sexeger_non_greedy(s)

n = 100_000
Benchmark.bm(18) do |x|
    x.report("scan greedy")        { n.times do; scan_greedy(s); end }
    x.report("scan non greedy")    { n.times do; scan_non_greedy(s); end }
    x.report("right index")        { n.times do; scan_greedy(s); end }
    x.report("sexeger non greedy") { n.times do; sexeger_non_greedy(s); end }
end
1 голос
/ 28 марта 2009

Простое решение без регулярных выражений:

string = "The quick red fox (frank,10) jumped over the lazy brown dog (ralph, 20)."
string[string.rindex('(')..string.rindex(')')]

Пример:

irb(main):001:0> string =  "The quick red fox (frank,10) jumped over the lazy brown dog (ralph, 20)."
=> "The quick red fox (frank,10) jumped over the lazy brown dog (ralph, 20)."
irb(main):002:0> string[string.rindex('(')..string.rindex(')')]
=> "(ralph, 20)"

И без скобок:

irb(main):007:0> string[string.rindex('(')+1..string.rindex(')')-1]
=> "ralph, 20"
1 голос
/ 28 марта 2009

Я бы попробовал это (здесь мое регулярное выражение предполагает, что первое значение является буквенно-цифровым, а второе - цифрой, отрегулируйте соответственно). Здесь сканирование получает все вхождения в виде массива, а -1 говорит нам, чтобы мы взяли только последний, который, кажется, именно то, что вы просите:

>> foo = "The quick red fox (frank,10) jumped over the lazy brown dog (ralph, 20)."
=> "The quick red fox (frank,10) jumped over the lazy brown dog (ralph, 20)."
>> foo.scan(/\(\w+, ?\d+\)/)[-1]
=> "(ralph, 20)"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...