Techioz Blog

Ruby: 置換部分は変数に含めて保存されますが、gsub を使用すると補間が発生しません

概要

  1. 私が書いたコード。
$str = '909090 aa bb cc dd ee ff 00 12345678 aa bb 12345678 aa bb cc dd ee ff 00 11 22 33 123456 FE 89'
puts $str
$str.gsub!(/\s+/, '')

search_1  = 'aa bb cc dd ee ff 00 (\S{8} aa bb \S{8} aa bb cc dd ee ff 00 11 22 33 \S{6}) (FF|FE) (89)'
puts search_1
search_1.gsub!(/\s+/, '')
replace_1 = '11 22 33 44 55 66 77 $1 $2 $3'
puts replace_1
replace_1.gsub!(/\s+/, '')

repls_1 = [
  [search_1, replace_1],
]


repls_1.each do |x|
  abc = $str.gsub(Regexp.new(x[0])) {
    x[1]
  }
  puts abc
end
  1. スクリプト実行結果
  909090 aa bb cc dd ee ff 00 12345678 aa bb 12345678 aa bb cc dd ee ff 00 11 22 33 123456 FE 89
  aa bb cc dd ee ff 00 (\S{8} aa bb \S{8} aa bb cc dd ee ff 00 11 22 33 \S{6}) (FF|FE) (89)
  11 22 33 44 55 66 77 $1 $2 $3

  90909011223344556677$1$2$3

、 の補間が行われません。解決する方法はありますか?ありがとう。

  1. \1 \2 \3 は使いたくないのですが、)

  2. 複数のパターンがありますが、ここでは 1 つの例のみを示します

  3. 一致する部品番号は固定されていません。これは です。………………..などの他のケースも考えられます。取得した部品番号と位置の両方でコードがこの変動をカバーできることを願っています。 。

解決策

、 を、以前の一致からのそれぞれのキャプチャに動的に置き換えることができます。

repls_1.each do |pattern, replacement|
  puts $str.gsub(Regexp.new(pattern)) {
    match_data = $~
    replacement.gsub(/\$(\d)/) { match_data[$1.to_i] }
  }
end

ただし、gsub には \1、\2、\3 後方参照による置換が組み込まれているため、これは基本的に車輪の再発明です。

gsub と互換性のある置換文字列を取得するには、単に , , を \1、\2、\3 に置き換える方がはるかに簡単です。 hBcnotation を保持したいので、実行時にこの置換を実行できます。 tr経由:

repls_1.each do |pattern, replacement|
  gsub_replacement = replacement.tr('$', '\\')
  puts $str.gsub(Regexp.new(pattern), gsub_replacement)
end

gsub で調整された置換文字列と実際のパターンを repls_1 配列にすでに格納することもできます。

# create actual pattern and adjust replacement string
repls_1.map! { |a, b| [Regexp.new(a), b.tr('$', '\\')] }

こうすることで、毎回調整を繰り返す必要がなくなり、交換がさらに簡単 (そして迅速) になります。

repls_1.each do |pattern, replacement|
  puts $str.gsub(pattern, replacement)
end

上記のコードでは、すべての $ が  に置き換えられることに注意してください。より高度な置換を行うには、別の正規表現を使用できます。次の数字を考慮します。

gsub_replacement = replacement.gsub(/\$(?=\d)/, '\\')