0

文字列を1回だけ読み取ることで、Rubyの文字列からいくつかの情報を抽出したいと思います(O(n)時間計算量)。

次に例を示します。

文字列は次のようになります。-location here -time 7:30pm -activity biking

この情報を入力したいRubyオブジェクトがあります。すべてのキーワードは既知であり、それらはすべてオプションです。

def ActivityInfo
  _attr_reader_ :location, :time, :activity

  def initialize(str)
    @location, @time, @activity = DEFAULT_LOCATION, DEFAULT_TIME, DEFAULT_ACTIVITY

    # Here is how I was planning on implementing this
    current_string = ""
    next_parameter = nil # A reference to keep track of which parameter the current string is refering to
    words = str.split
    while !str.empty?
      word = str.shift
      case word
      when "-location"
        if !next_parameter.nil?
          next_parameter.parameter = current_string # Set the parameter value to the current_string
          current_string = ""
        else
        next_parameter = @location
      when "-time"
        if !next_parameter.nil?
          next_parameter.parameter = current_string
          current_string = ""
        else
        next_parameter = @time
      when "-activity"
        if !next_parameter.nil?
          next_parameter.parameter = current_string
          current_string = ""
        else
        next_parameter = @time
      else
        if !current_string.empty?
          current_string += " "
        end
        current_string += word
      end
    end
  end   
end

つまり、基本的に、変数を別の変数またはメソッドの参照にする方法がわからないので、特定の値に設定できます。それとも、これを達成するための別のより効率的な方法がありますか?

ありがとう!

4

3 に答える 3

2

文字列は疑わしいほどコマンドラインのように見えますoptparse.

そうでない場合は、サンプル内のコマンドをハッシュに解析する簡単な方法を次に示します。

cmd = '-location here -time 7:30pm -activity biking'
Hash[*cmd.scan(/-(\w+) (\S+)/).flatten]

結果は次のとおりです。

{
    "location" => "here",
        "time" => "7:30pm",
    "activity" => "biking"
}

もう少し拡張します:

class ActivityInfo
  def initialize(h)
    @location = h['location']
    @time     = h['time'    ]
    @activity = h['activity']
  end
end
act = ActivityInfo.new(Hash[*cmd.scan(/-(\w+) (\S+)/).flatten])

act次のような ActivityInfo のインスタンスに設定されます。

#<ActivityInfo:0x101142df8
    @activity = "biking",
    @location = "here",
    @time = "7:30pm"
>

--

-OPは、コマンドにフラグが立てられていない、または複数の単語である状況に対処する方法を尋ねました。これらは同等ですが、スタイル的には最初のほうが好みです。

irb(main):003:0> cmd.scan(/-((?:location|time|activity)) \s+ (\S+)/x)
[
    [0] [
        [0] "location",
        [1] "here"
    ],
    [1] [
        [0] "time",
        [1] "7:30pm"
    ],
    [2] [
        [0] "activity",
        [1] "biking"
    ]
]

irb(main):004:0> cmd.scan(/-(location|time|activity) \s+ (\S+)/x)
[
    [0] [
        [0] "location",
        [1] "here"
    ],
    [1] [
        [0] "time",
        [1] "7:30pm"
    ],
    [2] [
        [0] "activity",
        [1] "biking"
    ]
]

コマンドが「場所で」のように複数の単語である場合:

irb(main):009:0> cmd = '-at location here -time 7:30pm -activity biking'
"-at location here -time 7:30pm -activity biking"
irb(main):010:0> 
irb(main):011:0* cmd.scan(/-((?:at \s location|time|activity)) \s+ (\S+)/x)
[
    [0] [
        [0] "at location",
        [1] "here"
    ],
    [1] [
        [0] "time",
        [1] "7:30pm"
    ],
    [2] [
        [0] "activity",
        [1] "biking"
    ]
]

さらに柔軟性が必要な場合は、Ruby のstrscanモジュールを見てください。これを使用して、文字列を分解し、コマンドとそのパラメーターを見つけることができます。

于 2012-07-17T00:14:27.917 に答える
1

文字列をオプション ハッシュに変換する

フラグとその値に簡単にアクセスしたい場合は、文字列を各フラグがキーであるハッシュに分割できます。例えば:

options = Hash[ str.scan /-(\w+)\s+(\S+)/ ]
=> {"location"=>"here", "time"=>"7:30pm", "activity"=>"biking"}

その後、値を直接参照するoptions['location']か (例: )、キーと値のペアでハッシュを反復処理できます。例えば:

options.each_pair { |k, v| puts "%s %s" % [k, v] }

メタプログラミングのダッシュ

わかりました、これは深刻なオーバーエンジニアリングですが、興味深いと思ったので、この質問に少し余分な時間を費やしました。以下が有用であると主張しているわけではありません。やってて楽しかったって言ってるだけ。

オプション フラグを解析し、一連の属性リーダーを動的に作成し、フラグまたは変数を個別に定義することなくいくつかのインスタンス変数を設定する場合は、メタプログラミングのダッシュでこれを行うことができます。

# Set attribute readers and instance variables dynamically
# using Kernel#instance_eval.
class ActivityInfo
  def initialize(str)
    options = Hash[ str.scan /-(\w+)\s+(\S+)/ ]
    options.each_pair do |k, v|
      self.class.instance_eval { attr_reader k.to_sym }
      instance_variable_set("@#{k}", v)
    end
  end
end

ActivityInfo.new '-location here -time 7:30pm -activity biking'
=> #<ActivityInfo:0x00000001b49398
 @activity="biking",
 @location="here",
 @time="7:30pm">

正直なところ、次のようなオプション ハッシュから変数を明示的に設定すると思います。

@activity = options['activity']`

意図をより明確に伝えます (そしてより読みやすくなります) が、代替手段があることは常に良いことです。あなたのマイレージは異なる場合があります。

于 2012-07-17T00:19:37.723 に答える
0

トールがあなたのために重いものを持ち上げることができるのに、なぜ車輪を再発明するのですか?

class ActivityInfo < Thor

  desc "record", "record details of your activity"
  method_option :location, :type => :string,   :aliases => "-l", :required => true
  method_option :time,     :type => :datetime, :aliases => "-t", :required => true
  method_option :activity, :type => :string,   :aliases => "-a", :required => true
  def record
    location = options[:location]
    time = options[:time]
    activity = options[:activity]

    # record details of the activity
  end

end

オプションは、指定したデータ型に基づいて解析されます。プログラムで呼び出すことができます。

task = ActivityInfo.new([], {location: 'NYC', time: Time.now, activity: 'Chilling out'})
task.record

またはコマンドラインから:thor activity_info:record -l NYC -t "2012-06-23 02:30:00" -a "Chilling out"

于 2012-07-17T11:44:49.167 に答える