रूबी रेगेक्स ग्रुप मिलान, 1 लाइन पर चर असाइन करें


125

मैं वर्तमान में कई चर में एक स्ट्रिंग rexp करने की कोशिश कर रहा हूँ। उदाहरण स्ट्रिंग:

ryan_string = "RyanOnRails: This is a test"

मैंने इसे 3 समूहों के साथ इस regexp के साथ मिलान किया है:

ryan_group = ryan_string.scan(/(^.*)(:)(.*)/i)

अब प्रत्येक समूह तक पहुँचने के लिए मुझे कुछ इस तरह करना होगा:

ryan_group[0][0] (first group) RyanOnRails
ryan_group[0][1] (second group) :
ryan_group[0][2] (third group) This is a test

यह बहुत हास्यास्पद लगता है और ऐसा लगता है कि मैं कुछ गलत कर रहा हूं। मैं इस तरह से कुछ करने में सक्षम होने की उम्मीद करूंगा:

g1, g2, g3 = ryan_string.scan(/(^.*)(:)(.*)/i)

क्या यह संभव है? या वहाँ एक बेहतर तरीका है कि मैं यह कैसे कर रहा हूँ?

जवाबों:


199

आप इसके लिए नहीं चाहते हैं scan, क्योंकि यह थोड़ा समझ में आता है। आप उपयोग कर सकते हैं String#matchजो किसी MatchDataवस्तु को वापस कर देगा , आप फिर #capturesकैप्चर के एरे को वापस करने के लिए कॉल कर सकते हैं । कुछ इस तरह:

#!/usr/bin/env ruby

string = "RyanOnRails: This is a test"
one, two, three = string.match(/(^.*)(:)(.*)/i).captures

p one   #=> "RyanOnRails"
p two   #=> ":"
p three #=> " This is a test"

ध्यान रखें कि यदि कोई मैच नहीं मिला है String#match, तो शून्य वापस आ जाएगा, इसलिए ऐसा कुछ बेहतर काम कर सकता है:

if match = string.match(/(^.*)(:)(.*)/i)
  one, two, three = match.captures
end

हालांकि scanइसके लिए बहुत कम अर्थ है। यह अभी भी काम करता है, आपको बस पहले दिए गए ऐरे को समतल करना होगा।one, two, three = string.scan(/(^.*)(:)(.*)/i).flatten


6
खबरदार कि अगर कोई मैच नहीं मिला है, तो रिटर्न निल से मेल करें और आपको निलेयर हो जाए। यदि आप रेल में हैं, तो मैं आपको बदलने का सुझाव देता हूं one, two, three = string.match(/(^.*)(:)(.*)/i).captures :one, two, three = string.match(/(^.*)(:)(.*)/i).try(:captures)
एंड्रिया सालिसीटी

5
@AndreaSalicetti मैंने अपना पोस्ट संपादित कर दिया है, मैं इसमें रेल-विशिष्ट कोड नहीं जोड़ रहा हूँ, इसलिए मैंने इसे लौटाए गए नील ऑब्जेक्ट को संभालने के लिए एक संस्करण के साथ बदल दिया है
ली जार्विस

3
आप नए &.ऑपरेटर को एक लाइन पर वापस लाने के लिए भी कर सकते हैं और यहां तक ​​कि दो बार इसका उपयोग कर सकते हैं जब केवल एक कैप्चर ग्रुप होता है। उदा ..,string.match(regex)&.captures&.first
गेरू शॉ

46

आप मैच या = ~ का उपयोग कर सकते हैं, जो आपको एक ही मैच देगा और आप मैच डेटा को उसी तरह एक्सेस कर सकते हैं या विशेष मिलान चर $ 1, $ 2, $ 3 का उपयोग कर सकते हैं

कुछ इस तरह:

if ryan_string =~ /(^.*)(:)(.*)/i
   first = $1
   third = $3
end

5
@ गैस्टॉन जो वास्तव में पर्ल से उत्पन्न मूल रेक्सएक्सपी सिंटैक्स है :)
ओलेक

28

आप अपने कब्जे वाले मैचों को नाम दे सकते हैं

string = "RyanOnRails: This is a test"
/(?<one>^.*)(?<two>:)(?<three>.*)/i =~ string
puts one, two, three

यदि आप स्ट्रिंग और रेगेक्स के क्रम को उलटते हैं तो यह काम नहीं करता है।


6

आपको यह तय करना होगा कि क्या यह एक अच्छा विचार है, लेकिन रूबी रेगेक्सप (स्वचालित रूप से) स्थानीय चर को परिभाषित कर सकता है आपके लिए कर सकता है!

मुझे अभी तक यकीन नहीं है कि यह सुविधा कमाल की है या पूरी तरह से पागल है, लेकिन आपका रेगेक्स स्थानीय चर को परिभाषित कर सकता है।

ryan_string = "RyanOnRails: This is a test"
/^(?<webframework>.*)(?<colon>:)(?<rest>)/ =~ ryan_string
# This defined three variables for you. Crazy, but true.
webframework # => "RyanOnRails"
puts "W: #{webframework} , C: #{colon}, R: #{rest}"

( Http://ruby-doc.org/core-2.1.1/Regexp.html पर एक नज़र डालें , "स्थानीय चर खोजे")।

नोट: जैसा कि एक टिप्पणी में कहा गया है, मैं देखता हूं कि @toonsend ( https://stackoverflow.com/a/21412455 ) इस सवाल का एक समान और पहले वाला उत्तर है । मुझे नहीं लगता कि मैं "चोरी" कर रहा था, लेकिन अगर आप प्रशंसा के साथ निष्पक्ष होना चाहते हैं और पहले जवाब का सम्मान करते हैं, तो स्वतंत्र महसूस करें :) मुझे उम्मीद है कि कोई जानवर नुकसान नहीं पहुंचा था।


यह उत्तर उल्लेखनीय रूप से stackoverflow.com/a/21412455/525478 के समान दिखता है , जो एक वर्ष से अधिक पुराना है ...
ब्रैड वेयर

@ ब्रैडवर्थ मुझे लगता है कि मैंने ऐसा नहीं देखा। लेकिन मैंने आपकी चिंताओं को शामिल करने के लिए अपना जवाब अपडेट किया।
फेलिक्स

5

scan() आपके स्ट्रिंग में रेगेक्स के सभी गैर-अतिव्यापी मिलान मिलेंगे, इसलिए अपने समूहों की एक सरणी को वापस करने के बजाय जैसे आप उम्मीद कर रहे हैं, यह सरणी की एक सरणी लौटा रहा है।

आप शायद बेहतर उपयोग कर रहे हैं match(), और फिर का उपयोग कर कब्जा की सरणी हो रही है MatchData#captures:

g1, g2, g3 = ryan_string.match(/(^.*)(:)(.*)/i).captures

हालाँकि आप भी ऐसा कर सकते हैं scan()यदि आप चाहते हैं:

g1, g2, g3 = ryan_string.scan(/(^.*)(:)(.*)/i)[0]
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.