Interpolacja ciągu znaków do wyrażenia regularnego

160

Muszę podstawić wartość ciągu w moim wyrażeniu regularnym w Rubim. Czy jest na to łatwy sposób? Na przykład:

foo = "0.0.0.0"
goo = "here is some other stuff 0.0.0.0" 
if goo =~ /value of foo here dynamically/
  puts "success!"
end
Chris Bunch
źródło
Czy próbujesz sprawdzić, czy foo jest podciągiem mazi? Myślę, że nie jest jasne, o co pytasz.
Neall
Jeśli tak, wystarczy goo.include? (Foo)!
glenn mcdonald
1
Nie, nie próbowałem sprawdzić, czy foo jest podciągiem mazi; Musiałem też zrobić trochę przechwytywania, więc dołączanie nie działało.
Chris Bunch,

Odpowiedzi:

274

To samo, co wstawianie ciągu.

if goo =~ /#{Regexp.quote(foo)}/
#...
Jonathan Lonowski
źródło
125

Zauważ, że Regexp.quotew Jon L. za odpowiedź jest ważna!

if goo =~ /#{Regexp.quote(foo)}/

Jeśli wybierzesz tylko „oczywistą” wersję:

if goo =~ /#{foo}/

wtedy kropki w tekście dopasowania są traktowane jako symbole wieloznaczne wyrażenia regularnego i "0.0.0.0"będą zgodne "0a0b0c0".

Zauważ również, że jeśli naprawdę chcesz tylko sprawdzić dopasowanie podłańcucha, możesz po prostu to zrobić

if goo.include?(foo)

który nie wymaga dodatkowego cytowania ani martwienia się o znaki specjalne.

glenn mcdonald
źródło
3
Zwróć uwagę, że odwrotność (nieużywanie .quote()) może być również przydatna, jeśli chcesz skonstruować wyrażenie regularne za pomocą ciągu.
Jesse
"jeśli naprawdę chcesz tylko sprawdzić dopasowanie podłańcucha, możesz po prostu zrobić if goo.include?(foo)" => True, gdy chcesz sprawdzić istnienie. Jeśli jesteś zainteresowany zastąpieniem i już korzystaniem z String.gsub, wówczas Regexp.quote może być jedyną opcją.
Isaac Betesh,
Aby dodać do Jesse na wypadek, gdyby nie było to oczywiste, oznacza to po prostu przekazanie ciągu znaków, do których nie potrzebujesz ucieczki Regexp.newlub Regexp.compile.
dylankb
Dziękuję za przydatne wyjaśnienie, dlaczego możemy chcieć skorzystać z Regexp. Cytat
Wylliam Judd
7

Prawdopodobnie Regexp.escape(foo)będzie to punkt wyjścia, ale jest to dobry powód, dla którego nie mogą korzystać z bardziej konwencjonalną ekspresję interpolacji: "my stuff #{mysubstitutionvariable}"?

Możesz też po prostu użyć !goo.match(foo).nil?z literałem.

JasonTrue
źródło
6
Regexp.compile(Regexp.escape(foo))
Markus Jarderot
źródło
3

Użyj Regexp.new:

if goo =~ Regexp.new(foo) # Evaluates to /0.0.0.0/
Jeremy Ruten
źródło
3

Oto ograniczona, ale użyteczna inna odpowiedź:

Odkryłem, że mogę łatwo wstawić do wyrażenia regularnego bez użycia Regexp.quote lub Regexp.escape, jeśli użyłem tylko apostrofów w moim ciągu wejściowym: (pasujący adres IP)

IP_REGEX = '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'

my_str = "192.0.89.234 blahblah text 1.2, 1.4" # get the first ssh key 
# replace the ip, for demonstration
my_str.gsub!(/#{IP_REGEX}/,"192.0.2.0") 
puts my_str # "192.0.2.0 blahblah text 1.2, 1.4"

pojedyncze cudzysłowy interpretują tylko znaki \\ i \ '.

http://en.wikibooks.org/wiki/Ruby_Programming/Strings#Single_quotes

Pomogło mi to, gdy musiałem kilkakrotnie użyć tej samej długiej części wyrażenia regularnego. Nie uniwersalne, ale moim zdaniem pasuje do przykładu pytania.

Plasmarob
źródło
jestem ciekawy, co będzie pomyślane o moim wpisie tutaj, ale wątpię, że będzie to teraz widoczne tak daleko tutaj.
Plasmarob
-2
foo = "0.0.0.0"
goo = "here is some other stuff 0.0.0.0" 

puts "success!" if goo =~ /#{foo}/
Mike Breen
źródło
2
Nie, to da błędne „prawda” dla „tutaj jest kilka innych rzeczy 070x0! 0”, ponieważ kropki są symbolami wieloznacznymi wyrażeń regularnych.
glenn mcdonald