【问题标题】:Array to String with specific format具有特定格式的数组到字符串
【发布时间】:2015-09-16 18:02:37
【问题描述】:

我有一个这样的哈希:

@password_constraints = {
  length: 'Must be at least 6 character long.',
  contain: [
      'one number',
      'one lowercase letter',
      'one uppercase letter.'
  ]
}

我想写一个方法来返回一个人类可读的字符串,这个字符串是由这个哈希构建的,就像这样:

必须至少有 6 个字符长。必须包含:一个数字、一个小写字母一个大写字母。

目前,我有一个非常冗长的方法,它使用 each 迭代 @password_constraints[:contain] 数组,并有几个条件来检查我是否必须放置 ,and 或什么都没有。

但我想要与join(', ') 几乎相同的行为,但最后一个分隔符必须是and

我正在寻找某种解决方案,例如带有特殊 join 的解决方案:

def password_constraints
  @password_constraints[:length] << ' Must contain.' << @password_constraints[:contain].join(', ') 
end

有没有办法让它更紧凑或更类似于 Ruby?

【问题讨论】:

    标签: arrays ruby string format


    【解决方案1】:

    您可以使用 splat 运算符拆分数组,如果只有一个字符串,则只需检查大小写:

    def message(constraints)
      *others, second_last, last = constraints[:contain]
      second_last += " and #{last}" unless last.nil?
      "#{constraints[:length]} Must contain: #{(others << second_last).join(', ')}"
    end
    
    @password_constraints = {
      length: 'Must be at least 6 character long.',
      contain: [
          'one number',
          'one lowercase letter',
          'one uppercase letter.'
      ]
    }
    
    message(@password_constraints)
    # => "Must be at least 6 character long. Must contain: one number, one lowercase letter and one uppercase letter." 
    
    # if @password_constraints[:contain] = ['one lowercase letter', 'one uppercase letter.']
    message(@password_constraints)
    # => "Must be at least 6 character long. Must contain: one lowercase letter and one uppercase letter." 
    
    # if @password_constraints[:contain] = ['one lowercase letter']
    message(@password_constraints)
    # => "Must be at least 6 character long. Must contain: one lowercase letter"
    

    【讨论】:

    • 这绝对是一个更像 Ruby 的答案。为了清楚起见,最好使用 splat 运算符拉最后一个元素,并使用字符串插值而不是串联。如果您真的想变得更时髦,您可以将输出字符串中的第二位内插代码更改为"#{(others &lt;&lt; second_last) * ', '}",但这很难阅读。
    • 这样一个优雅的解决方案而且非常紧凑。这绝对是我要找的。非常感谢!
    • 我更新解决方案:方法的第二行应该被删除,它应该在第三行的末尾,以便不修改当前的哈希。 *others, second_last, last = constraints[:contain]"#{constraints[:length]} Must contain: #{(others &lt;&lt; second_last).join(', ')}" &lt;&lt; " and #{last}" unless last.nil?
    • 我不知道...您可能应该针对这个新问题创建另一个关于 SO 的问题。但在此之前,如果你使用 Rails,你要检查Array#to_sentence
    • 感谢Doguita的帮助,我已经找到了问题所在。问题是我每次调用函数时实际上都是在修改哈希值哈哈。问候!
    【解决方案2】:

    为了简洁起见,我会在这里使用猴子补丁(是的,我的 join_requirements 方法可能看起来更好一点)。

    class Array
      def join_requirements
        result = ""
        self.each do |requirement|
          if requirement == self.last
            result << "and " << requirement
          else
            result << requirement + ", "
          end
        end
        result
      end
    end
    

    然后在你的代码中你会看到这个:

    contain = ['one number','one lowercase letter','one uppercase letter.']
    puts contain.join_requirements
    # => one number, one lowercase letter, and one uppercase letter.
    

    【讨论】:

    • 非常感谢您提供此解决方案,我以前从未听说过猴子补丁。它完美地工作。问题是在这个项目中,我只需要一种方法的这种行为。但是在其他“和问题”更频繁的项目中,这将是最好的解决方案!再次感谢。
    • 虽然这行得通,但它并没有更紧凑,也不再像“Ruby”了。
    • @theTinMan 很公平,我在答案中确实提到这不是编写它的最佳方式。我只是想提供猴子补丁作为解决方案。
    【解决方案3】:

    Here 是 Ruby 中一个有趣的速记小技巧,您可以使用数组来减少对冗长的 join 的需求。

    def password_constraints
      @password_constraints[:length] << ' Must contain.' << @password_constraints[:contain] * ", "
    end
    

    Array 类的 * 运算符显式检查 string 第二个操作数,然后转换为在幕后调用 join

    【讨论】:

    • 感谢您提供的信息,ruby 中有很多魔法!哈哈
    • 这会引发错误,即使已修复,也不要在结尾添加“和”
    猜你喜欢
    • 2016-10-13
    • 1970-01-01
    • 1970-01-01
    • 2019-05-02
    • 2017-04-29
    • 1970-01-01
    • 2020-07-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多