【问题标题】:How to validate a string whether it contain valid Ruby Symbol literal如何验证字符串是否包含有效的 Ruby 符号文字
【发布时间】:2021-10-22 16:08:25
【问题描述】:

我有一些字符串输入,我想验证它是否是有效的 Ruby 符号文字。如果是,则将其转换为符号。否则返回传递的字符串。

例子,

def parse_symbol(str)
  ...          # Validate and convert to Symbol
  # Return Symbol if valid Symbol literal
  # Otherwise return str
end

input1 = ':foo_bar'   #=> Valid Symbol
parse_symbol(input1)  #=> :foo_bar

input2 = ':"foo bar"' #=> Valid Symbol
parse_symbol(input2)  #=> :"foo bar"

input3 = ':foo bar'   #=> Invalid
parse_symbol(input3)  #=> :foo bar

input4 = '::"foo_bar"'   #=> Invalid
parse_symbol(input4)  #=> ::"foo_bar"

...   # all other possible valid and invalid symbol literal goes here

str.to_sym # 将每个字符串转换成符号形式

编辑

eval 是在这里使用的昂贵工具吗?

eval(str).is_a?(Symbol) 救援 str

【问题讨论】:

  • 为什么str 包含符号文字?您不能只传递字符串内容并使用to_sym 将其转换为符号吗?例如。 str.to_sym 假设 str 包含 'foo_bar' 而不是 ':foo_bar'(尽管后者也可以使用)。或者你是元编程? (定义创建方法/类的辅助方法。)
  • 字符串从何而来?为什么你需要将它翻译成一个符号,为什么只在某些情况下?这对我来说听起来像是一个 xy 问题。

标签: ruby


【解决方案1】:

我建议为此使用真正的解析器。

require 'parser/current'
require 'minitest/autorun'

def parse_symbol(str)
  ast = Parser::CurrentRuby.parse(str)
  if ast.type == :sym
    ast.children[0]
  else
    str
  end
rescue Parser::SyntaxError
  str
end

class TestAnswer < Minitest::Test
  def test_1
    assert_equal :foo_bar, parse_symbol(':foo_bar')
  end

  def test_2
    assert_equal :"foo bar", parse_symbol(':"foo bar"')
  end

  def test_3
    assert_equal ":foo bar", parse_symbol(':foo bar')
  end

  def test_4
    assert_equal '::"foo_bar"', parse_symbol('::"foo_bar"')
  end
end

【讨论】:

    【解决方案2】:
    def parse_symbol(str)
      result = str.scan /^\:(((@@|@|\$)?[a-zA-Z_]+[a-zA-Z0-9_]*[!\?]?)|(\$([:.><\?!\$\\\/'"@`~\+\;]|\-\w))|(\$[0-9]+)|(<|>|\[\])|"(.*)"|'(.*)')$/
      return str unless !result.empty?
    
      result[0].drop(1).each do |part|
        return part.to_sym unless part.nil?
      end
    end
    

    【讨论】:

    • 符号:a1:"007"有什么问题?
    • 哈哈我的错,它被编辑了
    • 或(修改后)':"&amp;"''a!'?
    • 查看接受的答案here
    • 感谢您的评论,@CarySwoveland
    【解决方案3】:

    使用这样的正则表达式。

    def parse_symbol(str)
      if str ~= /:([^:\s]+||"[^:]+")/
        return str.to_sym
      else
        return str
      end
    end
    

    eval 是在这里使用的昂贵工具吗?

    它可能不会那么昂贵,但根据输入的来源,它可能很危险。

    【讨论】:

    • 这个答案(在我写这篇评论的时候)有一个语法错误(~=应该是=~),更重要的是,没有通过input2的测试,其值为':"foo bar"'。正确的输出是:"foo bar",但这个答案会产生:":\"foo bar\""
    • 我已经对此进行了测试(使用更正的语法=~),它可以转换所有输入字符串,包括parse_symbol('::foo bar') #=&gt; :"::foo bar"。这不是预期的输出。
    • 这匹配":"。为什么?因为你有||,而不是|。一行中的两个管道匹配一个空字符串。即使:007 不是有效符号,您的正则表达式也匹配":007"。另外,捕获组的意义何在?最后,您显然没有测试您的答案,这是不可原谅的。我很少对答案投反对票,但您的答案确实值得一票。
    猜你喜欢
    • 1970-01-01
    • 2021-05-04
    • 1970-01-01
    • 2018-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-20
    • 2012-02-24
    相关资源
    最近更新 更多