Совпадающая позиция в gsub или scan

Каков наилучший способ добиться совпадающей позиции (индекса, который будет возвращен =~) для каждого совпадения при использовании gsub или scan?


person sawa    schedule 03.03.2012    source источник
comment
возможный дубликат Ruby String#scan эквивалентен возврату MatchData, не совсем точный дублируется, но ответы те же.   -  person mu is too short    schedule 03.03.2012


Ответы (2)


"hello".gsub(/./) { Regexp.last_match.offset(0).first }
 => "01234" 

См. Regexp.last_match и MatchData.

person Nash Bridges    schedule 04.03.2012
comment
hello hello.gsub(/hello/) { Regexp.last_match.offset(0).first } return 0 6 что нужно сделать, чтобы получить 0 1? - person vaichidrewar; 27.04.2013

Я подошел к этой проблеме с другой стороны и не смог придумать достойного решения (то есть понятного, поддерживаемого), чтобы сделать это с помощью gsub или scan (оба встроенные методы класса String). Поэтому я спросил: «Почему так?...» и стал искать более естественные альтернативы (спасибо Нэшу за указание общего направления!):

#!/usr/bin/env ruby
# -*- encoding: utf-8 -*-

# capture_all_matches.rb
#
# Copyright © 2015 Lorin Ricker <[email protected]>
#
# This program is free software, under the terms and conditions of the
# GNU General Public License published by the Free Software Foundation.
# See the file 'gpl' distributed within this project directory tree.

# This sample code demonstrates three ways to capture *all* of the offsets
# [begin,end,length] data for *all* matches scanned in a source string.

# Of course, each/any of the below examples could be turned into a class method
# of String &/or Regexp -- One wonders why these are not part of the built-in
# classes/methods?...

# An example source string (any will do):
s = "The fox hides in the box full of sox eating lox."
#       4^                  25^   31^

# Use the literal pattern /f/ as an example --
# there are three "f"s in the sample source string;
# see indexes above...
p = /f/

# 1. Just report an array of the begin (start) position of each match:
mpos = []
m = i = 0
m = p.match( s, i ) { |k| j = k.begin(0); i = j + 1; mpos << j } while m
p mpos   # => [4, 25, 31]

# 2. Make an array containing elements [begin,end] of matched substrings:
mpos = []
m = i = 0
m = p.match( s, i ) { |k| j = k.offset(0); i = j[0] + 1; mpos << j } while m
p mpos   # => [[4, 5], [25, 26], [31, 32]]

# 3. Make an array containing elements [begin,end,length] of matched substrings:
mpos = []
m = i = 0
m = p.match( s, i ) { |k| j = k.offset(0); i = j[0] + 1;
                          j << j[1] - j[0]; mpos << j    } while m
p mpos   # => [[4, 5, 1], [25, 26, 1], [31, 32, 1]]

Продемонстрируйте это, вставив приведенное выше в исходный файл Ruby (например, capture_all_matches.rb), затем:

$ ruby capture_all_matches.rb

Обратите внимание, что метод соответствия RegExp можно (повторно) запускать с произвольного смещения в исходной строке, так что это просто вопрос захвата этого «последнего сопоставленного смещения» и повторения оттуда.

Нужно только начальное смещение каждого совпадения, начало и конец или длина начала и конца? Сверните свой собственный результирующий массив результатов.

Надеюсь это поможет.

person Lorin Ricker    schedule 19.10.2015
comment
Я надеюсь, что вы понимаете, что вы используете двойную лицензию на этот код под CC BY-SA и GPL, когда публикуете его здесь. - person ArtOfCode; 19.10.2015