Ruby에서 정규식의 모든 항목을 일치시키는 방법
루비에서 정규식의 모든 일치를 빠르게 찾을 수 있는 방법이 있습니까?Ruby STL에서 Regex 객체를 살펴보았지만 구글에서 검색을 해보지 못했습니다.
사용하면 다음과 같은 이점을 얻을 수 있습니다.
string.scan(/regex/)
일치하는 문자열을 모두 찾으려면 String의 방법을 사용합니다.
str = "A 54mpl3 string w1th 7 numb3rs scatter36 ar0und"
str.scan(/\d+/)
#=> ["54", "3", "1", "7", "3", "36", "0"]
원하는 경우 Regexp에서 반환하는 개체 유형입니다.match
사용: 서드사, 용메:
str.to_enum(:scan, /\d+/).map { Regexp.last_match }
#=> [#<MatchData "54">, #<MatchData "3">, #<MatchData "1">, #<MatchData "7">, #<MatchData "3">, #<MatchData "36">, #<MatchData "0">]
사용의 MatchData
다음과 같은 방법을 사용할 수 있습니다.offset
:
match_datas = str.to_enum(:scan, /\d+/).map { Regexp.last_match }
match_datas[0].offset(0)
#=> [2, 4]
match_datas[1].offset(0)
#=> [7, 8]
자세한 내용은 다음 질문을 참조하십시오.
- "문자열에 있는 모든 Ruby 정규식에 대한 일치 데이터를 가져오려면 어떻게 해야 합니까?"
- "이름 지정된 캡처 지원이 있는 열거자와 일치하는 루비 정규식"
- "Ruby에서 각 매치의 출발점을 찾는 방법"
변수에 특수변대한읽기에$&
,$'
,$1
,$2
루비에서도 도움이 될 것입니다.
그룹이 있는 regexp인 경우:
str="A 54mpl3 string w1th 7 numbers scatter3r ar0und"
re=/(\d+)[m-t]/
String String's 사할수있다니를 할 수 .scan
일치하는 그룹을 찾는 방법:
str.scan re
#> [["54"], ["1"], ["3"]]
일치하는 패턴 찾기
str.to_enum(:scan,re).map {$&}
#> ["54m", "1t", "3r"]
사용할 수 있습니다.string.scan(your_regex).flatten
정규식에 그룹이 포함된 경우 정규식은 단일 일반 배열로 반환됩니다.
string = "A 54mpl3 string w1th 7 numbers scatter3r ar0und"
your_regex = /(\d+)[m-t]/
string.scan(your_regex).flatten
=> ["54", "1", "3"]
정규식은 명명된 그룹일 수도 있습니다.
string = 'group_photo.jpg'
regex = /\A(?<name>.*)\.(?<ext>.*)\z/
string.scan(regex).flatten
사용할 수도 있습니다.gsub
MatchData를 원하는 경우 한 가지 방법만 더 사용할 수 있습니다.
str.gsub(/\d/).map{ Regexp.last_match }
그룹이 ()
다른 목적을 위한 정규식 내부, 제안된 해결책String#scan
그리고.String#match
문제가 있음:
String#scan
캡처 그룹 내에 있는 것만 가져옵니다.String#match
매치만 매치는 합니다.String#matches
모든 일치 항목을 가져옵니다.
이 경우 캡처 그룹을 고려하지 않고 정규식에 맞는 솔루션이 필요합니다.
String#matches
정교함을 사용하여 원숭이 패치를 적용할 수 있습니다.String
class, 구현을 합니다.String#matches
이 방법은 세분화를 사용하는 클래스의 범위 내에서 사용할 수 있습니다.그것은 루비의 몽키 패치 수업으로 가는 믿을 수 없는 방법입니다.
세우다
/lib/refinements/string_matches.rb
# This module add a String refinement to enable multiple String#match()s
# 1. `String#scan` only get what is inside the capture groups (inside the parens)
# 2. `String#match` only get the first match
# 3. `String#matches` (proposed function) get all the matches
module StringMatches
refine String do
def matches(regex)
scan(/(?<matching>#{regex})/).flatten
end
end
end
사용.
rails c
> require 'refinements/string_matches'
> using StringMatches
> 'function(1, 2, 3) + function(4, 5, 6)'.matches(/function\((\d), (\d), (\d)\)/)
=> ["function(1, 2, 3)", "function(4, 5, 6)"]
> 'function(1, 2, 3) + function(4, 5, 6)'.scan(/function\((\d), (\d), (\d)\)/)
=> [["1", "2", "3"], ["4", "5", "6"]]
> 'function(1, 2, 3) + function(4, 5, 6)'.match(/function\((\d), (\d), (\d)\)/)[0]
=> "function(1, 2, 3)"
의배을반니다합환열의 합니다.MatchData
#scan
매우 제한적입니다. 단순 문자열 배열만 반환합니다!
훨씬 더 강력하고 유연하게 스토리지 어레이를MatchData
물건들.
두 가지 접근 방식(동일한 논리 사용)을 제공하겠습니다. 하나는 PORO를 사용하고 다른 하나는 Monkey Patch를 사용합니다.
PORO:
class MatchAll
def initialize(string, pattern)
raise ArgumentError, 'must pass a String' unless string.is_a?(String)
raise ArgumentError, 'must pass a Regexp pattern' unless pattern.is_a?(Regexp)
@string = string
@pattern = pattern
@matches = []
end
def match_all
recursive_match
end
private
def recursive_match(prev_match = nil)
index = prev_match.nil? ? 0 : prev_match.offset(0)[1]
matching_item = @string.match(@pattern, index)
return @matches unless matching_item.present?
@matches << matching_item
recursive_match(matching_item)
end
end
용도:
test_string = 'a green frog jumped on a green lilypad'
MatchAll.new(test_string, /green/).match_all
=> [#<MatchData "green", #<MatchData "green"]
몽키패치
저는 일반적으로 원숭이 패칭을 용납하지 않지만, 이 경우에는:
- 패치를 자체 모듈로 "통합"하여 올바른 방식으로 작업하고 있습니다.
- 저는 이 접근법을 선호합니다. 왜냐하면
'string'.match_all(/pattern/)
보다 직관적이고(그리고 훨씬 더 멋져 보입니다)MatchAll.new('string', /pattern/).match_all
module RubyCoreExtensions
module String
module MatchAll
def match_all(pattern)
raise ArgumentError, 'must pass a Regexp pattern' unless pattern.is_a?(Regexp)
recursive_match(pattern)
end
private
def recursive_match(pattern, matches = [], prev_match = nil)
index = prev_match.nil? ? 0 : prev_match.offset(0)[1]
matching_item = self.match(pattern, index)
return matches unless matching_item.present?
matches << matching_item
recursive_match(pattern, matches, matching_item)
end
end
end
end
새 파일을 만들고 패치를 배치하는 것이 좋습니다(레일을 사용하는 경우)./lib/ruby_core_extensions/string/match_all.rb
패치를 사용하려면 패치를 사용할 수 있어야 합니다.
# within application.rb
require './lib/ruby_core_extensions/string/match_all.rb'
그런 다음 반드시 다음에 포함시킵니다.String
class (이것을 원하는 곳에 놓을 수 있습니다. 하지만 예를 들어, 위에서 방금 작성한 require statement 바로 아래에 있습니다.먼저 가세요.include
한 번만 사용하면 포함한 클래스 외부에서도 모든 곳에서 사용할 수 있습니다.
String.include RubyCoreExtensions::String::MatchAll
용도: 이제 사용할 때#match_all
다음과 같은 결과를 얻을 수 있습니다.
test_string = 'hello foo, what foo are you going to foo today?'
test_string.match_all /foo/
=> [#<MatchData "foo", #<MatchData "foo", #<MatchData "foo"]
test_string.match_all /hello/
=> [#<MatchData "hello"]
test_string.match_all /none/
=> []
여러 항목을 일치시키고 각 항목에 대한 유용한 정보(예: 항목 시작 및 종료 인덱스)를 얻을 때 특히 유용합니다.match.offset(0) => [first_index, last_index]
)
언급URL : https://stackoverflow.com/questions/80357/how-to-match-all-occurrences-of-a-regular-expression-in-ruby
'programing' 카테고리의 다른 글
CSS 선택기 "~"는 무엇을 의미합니까? (0) | 2023.06.03 |
---|---|
테스트 환경에서 Rails 콘솔을 실행하고 test_helper.rb를 로드하는 방법은 무엇입니까? (0) | 2023.06.03 |
Passport.js - 오류: 사용자를 세션으로 직렬화하지 못했습니다. (0) | 2023.06.03 |
POSTGRESQL에서 DATE에서 연도를 추출하는 방법 (0) | 2023.06.03 |
레일즈 앱에 대한 사용자 지정 구성 옵션을 만드는 가장 좋은 방법은 무엇입니까? (0) | 2023.06.03 |