在 Rails 中从字符串中间提取子字符串

Extracting substring from the middle of a string in Rails

提问人:Donslaught 提问时间:7/28/2023 更新时间:7/28/2023 访问量:61

问:

我正在尝试从作为字符串返回的类类型中提取子字符串:

'::Pos::EmailNotice'
'Pos::EmailNotice'
'::Pos::CallNotice'
'Pos::CallNotice'

因此,如果我得到一个字符串“Pos::{type}Notice”,我需要以{type}结束。

我尝试使用和,但我希望它比这更动态,以防万一命名空间被更改或我们将来添加更多类型的通知。#slice#delete_prefix#delete_suffix

我尝试在这里搜索,但我找不到任何答案来解释如何在这样的情况下提取文本。

Ruby-on-Rails 红宝石 字符串

评论


答:

0赞 Andre Wildberg 7/28/2023 #1

测试字符串

str = ['::Pos::EmailNotice', 'Pos::EmailNotice', 
  '::Pos::CallNotice', 'Pos::CallNotice', 'Pos::CallText']

gsub

str.map {|i| i.gsub /.*::|(Notice|Text)$/, ""}

["Email", "Email", "Call", "Call", "Call"]
1赞 smathy 7/28/2023 #2

假设它总是以 结尾,那么这可能是最简单的:Notice

main> %w[ ::Pos::EmailNotice Pos::EmailNotice ::Pos::CallNotice Pos::CallNotice ].map do |s|
main>   s.match(/([^:]+)Notice/)[1]
main> end
["Email", "Email", "Call", "Call"]

这基本上是说“所有非':'字符在'通知'之前”。

评论

1赞 Stefan 7/28/2023
还有,当没有找到匹配项时,它只是返回。您可能希望添加一个锚点来匹配字符串的末尾。s[/([^:]+)Notice/, 1]nil\z
0赞 smathy 7/28/2023
哇,TIL,谢谢!我一直在做一件事,但这是一个非常好的语法。if x = s.match ... x[1]
1赞 Cary Swoveland 7/28/2023 #3
arr = [ "::Pos::EmailNotice",
        "Pos::EmailNotice", 
        "::Pos::CallNotice",
        "Pos::CallNotice"
      ]
arr.map { |str| str[/[^:]*(?=Notice\z)/] }
  #=> ["Email", "Email", "Call", "Call"]

演示

该演示采用 PCRE 正则表达式引擎。虽然在某些方面与 Ruby 的 Onigmo 正则表达式引擎不同,但在这种情况下,它们给出了相同的结果。我使用了行尾锚点 () 而不是字符串末尾锚点 () 来针对多个字符串测试表达式。$\z

它使用带有正则表达式作为参数的 String#[] 方法。


正则表达式为“匹配除 () 以外的零个或多个 () 字符,在字符串 () 末尾后跟文字”Notice”。*^\z

(?=Notice\z)是一种积极的展望

您可能希望将光标悬停在链接处正则表达式的每个部分上,以获取其功能的说明。

1赞 Stefan 7/28/2023 #4

Rails 提供了 String#demodulize 来剥离模块中的命名空间:

'::Pos::EmailNotice'.demodulize #=> "EmailNotice"
'Pos::EmailNotice'.demodulize   #=> "EmailNotice"
'::Pos::CallNotice'.demodulize  #=> "CallNotice"
'Pos::CallNotice'.demodulize    #=> "CallNotice"

您可以将其与 delete_suffix! 一起使用,例如

string = '::Pos::EmailNotice'

string.demodulize.delete_suffix!('Notice')
#=> "Email"

另一种方法是将字符串转换为实际的类,并让它实现一个你可以调用的方法,例如:type

module Pos
  class EmailNotice
    def self.type
      :email
    end
  end
end

然后你可以使用 Rails 的 String#constantize

'::Pos::EmailNotice'.contantize.type #=> :email
'Pos::EmailNotice'.contantize.type   #=> :email

或者通过 Module#const_get 使用纯 Ruby:

Object.const_get('::Pos::EmailNotice').type #=> :email
Object.const_get('Pos::EmailNotice').type   #=> :email