6

Ruby (1.9.3) で基本的なトランスレータを作成しています。ローカル テスト ファイル (「a.txt」) から取得し、gsub を使用して特定の一致を置き換え、現代英語から中/初期現代英語への翻訳を模倣しています。読みやすさの問題に遭遇しました:

大量の gsub の使用状況を読みやすくするにはどうすればよいですか? で始まる複数の行を使用しようとしました

def translate 
  @text.gsub(/my/, 'mine')
  @text.gsub(/\sis\s/, ' be ')
end

ただし、これは最終的な gsub のみを出力します。2 番目のリクエストが最初のリクエストを上書きするとしか思えません。gsub リクエストの膨大な行を作成することは避けたいのですが、適切な答えが見つからないようです。

これが私の現在のプログラムのサンプルです:

lines = File.readlines('a.txt')
@text = lines.join

def translate 
  @text.gsub(/my/, 'mine').gsub(/\sis\s/, ' be ').gsub(/y\s/, 'ye ').gsub(/t\s/, 'te ').gsub(/t\,/, 'te,').gsub(/t\./, 'te.')
end

puts translate

このリクエストが完全に基本的なものであると思われる場合は、事前にお詫び申し上げます。乾杯!

4

5 に答える 5

6

このString#gsubメソッドは、置換が行われた文字列の新しいコピーを返し、元の文字列は変更されません。最初の例の両方の置換が行われましたが、最初の結果は何にも割り当てられていないため破棄されます。2 番目の結果は、メソッドの結果として返されます。

代わりに#gsub!メソッドを使用すると、置換の結果で元の文字列が変更され、複数の置換をより簡単に行うことができます。

def translate 
  @text.gsub!(/my/, 'mine')
  @text.gsub!(/\sis\s/, ' be ')
  @text
end

オブジェクトの属性を変更したくない場合は、メソッドを で開始し、メソッドの残りの部分で属性の代わりに変数をtext = @text.dup使用できます。text@text

于 2012-11-25T23:17:18.433 に答える
6

2 番目の呼び出しは、最初の呼び出しをオーバーライドしません。最初の呼び出しは@text、置換が行われた のコピーを返しますが、その戻り値で何もしていません。を変更する場合は、代わり@textに を使用する必要がありますgsub!。を変更したくない場合は、代わりに呼び出し@textをチェーンする必要があります。gsubたとえば、マッピング Hash from slivu's answer@textがある場合、これはインスタンス変数を実際に変更せずに翻訳されたテキストを返します。

def translate
  RegexMap.inject(@text) do |string, mapping|
    string.gsub(*mapping)
  end
end

に渡されたブロックは、injectマッピング ( のキーと値のペアRegexMap) ごとに 1 回呼び出されます。1 回目stringは、に渡される値inject、つまり@text. その後、後続の各呼び出しは、渡された前の呼び出しの戻り値をそのstring値として取得します。つまり、これを行ったかのようですが、一連のマッピングをより簡単に構成できます。

@text.gsub(/my/,'mine').gsub(/\sis\s/, ' be ').gsub(/y\s/,'ye ').gsub....
于 2012-11-25T23:49:14.623 に答える
5

もっと読みやすい?

次に、マップを作成してループを使用することを検討しますか?

RegexMap = {
  /my/     => 'mine',
  /\sis\s/ => ' be ',
  /y\s/    => 'ye ',
  /t\s/    => 'te ',
  /t\,/    => 'te,',
  /t\./    => 'te.',
}
text = '123 my 456 is 123y 456t 123t, 456t.'
RegexMap.each_pair {|f,t| text = text.gsub(f, t)}
puts text

#=> 123 mine 456 be 123ye 456te 123te, 456te.

更新:マークが示唆したように、使用gsub!すると冗長なコピー/割り当て操作が回避されます:

RegexMap.each_pair {|f,t| text.gsub! f, t}

これが実際のデモです

于 2012-11-25T23:30:54.743 に答える
1

特定のパターン、つまり単語を常に変換している場合は、単純な一致パターンを作成し、単語に応じてgsub一致パターンごとに 1 回実行するだけに置き換えることができます。

def translate 
  @text
  .gsub(/[ \t]+/, " ")
  .gsub(/\w+/,
    "my" => "mine",
    "is" => "be",
    "y" => "ye",
    "t" => "te"
  )
end

これは、 を複数回反復するよりもはるかに高速ですgsub

于 2012-11-26T05:55:43.587 に答える
0

slivuのアイデアに基づいて、Perlのような代替手段を次に示します。

@text = '123 my 456 is 123y 456t 123t, 456t.'

def s(regex, string)
   @text.gsub!(regex, string)
end

s /my/, 'mine'
s /\sis\s/, ' be '
s /y\s/, 'ye '
s /t\s/, 'te '
s /t\,/, 'te,'
s /t\./, 'te.'

puts @text
于 2012-11-26T01:00:11.277 に答える