Ruby从字符串数组中提取子字符串

Ruby从字符串数组中提取子字符串,ruby,substring,Ruby,Substring,我有一个字符串数组 irb(main):009:0* str_arr => ["hello how are you?", "I am fine.What are you doing?", "Hey, I am having a haircut. See you at Hotel KingsMen at 10 am."] 我正试图从中提取一些信息。酒店的名称和时间 irb(main):010:0> q = str_arr[2].scan(/(.*)Hotel(.*)at(.*)\./

我有一个字符串数组

irb(main):009:0* str_arr
=> ["hello how are you?", "I am fine.What are you doing?", "Hey, I am having a haircut. See you at Hotel KingsMen at 10 am."]
我正试图从中提取一些信息。酒店的名称和时间

irb(main):010:0> q = str_arr[2].scan(/(.*)Hotel(.*)at(.*)\./)
=> [["Hey, I am having a haircut. See you at ", " KingsMen ", " 10 am"]]
问题是我无法将索引修正为2。我需要这样的东西:

irb(main):023:0> str_arr.each { |str| $res = str.scan(/(.*)Hotel(.*)at(.*)\./) }
=> ["hello how are you?", "I am fine.What are you doing?", "Hey, I am having a haircut. See you at Hotel KingsMen at 10 am."]
irb(main):024:0> $res
=> [["Hey, I am having a haircut. See you at ", " KingsMen ", " 10 am"]]
但我不想使用全局变量。有什么改进我的代码的建议吗

s = ["hello how are you?", "I am fine.What are you doing?", "Hey, I am having a haircut. See you at Hotel KingsMen at 10 am."]
s.join.scan(/Hotel\s(.+)?\sat\s(.+)?\./).flatten
#=> ["KingsMen", "10 am"]
正则表达式说明:

  • \s
    -任何空白字符

  • -任何字符,
    +
    -任何字符中的一个或多个,
    ()
    -捕获其中的所有内容,因此
    (.+)
    -捕获一个或多个字符

  • a?
    表示零或
    a


  • 您也可以像这样使用select方法

    [
      "hello how are you?", "I am fine.What are you doing?",
      "Hey, I am having a haircut. See you at Hotel KingsMen at 10 am."
    ].select{|str| str =~ /Hotel\s(.+)?\sat\s(.+)?\./}
    
    #=>  ["Hey, I am having a haircut. See you at Hotel KingsMen at 10 am."]
    

    如果您希望保留当前解决方案,并且不希望使用全局变量,那么我建议您使用“减少”方法:

    str = ["hello how are you?", "I am fine.What are you doing?", "Hey, I am having a haircut. See you at Hotel KingsMen at 10 am."]
    
    str.reduce([]) do |res, s|
        res == [] ? s.scan(/(.*)Hotel(.*)at(.*)\./) : res
    end
    # => [["Hey, I am having a haircut. See you at ", " KingsMen ", " 10 am"]]
    
    在我看来,这使得用于保存和查找结果的临时变量尽可能地局部化。

    这是您的数组:

    arr = ["hello how are you?",
           "I am fine. What are you doing?",
           "Hey, I am having a haircut. See you at Hotel KingsMen at 10 am."]
    
    第一步是将元素连接到字符串中。我选择使用一个空间作为分隔符,但您可以使用其他东西:

    str = arr.join(' ')
      #=> "hello how...doing? Hey,...haircut. See you at Hotel KingsMen at 10 am." 
    
    在不丧失一般性的情况下,假设该字符串是以下字符串之一:

    str1 = "See you at Hotel KingsMen at 10 am."  
    str2 = "See you at 10:15am at Kingsmen hotel on Bloor Street."  
    
    哪家酒店?

    让我们先看看如何获得酒店的名称。我们需要一个能同时处理这两个字符串的方法。我们假设酒店的名称只有两个词,其中一个词是“hotel”,但我们不知道这两个词中的哪一个先出现,我们允许“hotel”以大写或小写字母开头

    我们在
    str1
    中看到,它可能是“在酒店”或“酒店金门”,而在
    str2
    中,它可能是“金斯敦酒店”或“酒店on”。正确的结果是通过合理假设“hotel”以外的单词大写而得到的

    这里有一种方法:

    def hotel(str)
      str[/\b[hH]otel\s+\K[A-Z][a-zA-Z]*|[A-Z][a-zA-Z]*(?=\s[Hh]otel\b)/]
    end
    
    hotel(str1) #=> "KingsMen" 
    hotel(str2) #=> "Kingsmen" 
    
    在这里:

    • \b
      是(零宽度)分词
    • \K
      表示匹配前面的内容,但不包括在返回的匹配中
    • |
      表示匹配前面或后面的内容
    • (?=\s[Hh]otel\b)
      是一种(“零宽度”)正向前瞻,表示必须紧跟在前面的内容之后,但不属于匹配的一部分
    什么时候?

    在这里,我们必须对时间的表达方式做出假设。“中午”、“1100小时”和“14:21”是否有可能?好的,这只是一个练习,让我们假设这是一个12小时的时钟,有小时,也可能有分钟,但没有秒

    我们可以使用以下正则表达式提取该信息:

    def time(str)
      str[/\b(?:1[012]|[1-9])(?::[0-5]{2})?\s?(?:[ap]m?)/i]
    end
    
    time(str1) #=> "10 am" 
    time(str2) #=> "10:15am" 
    
    在这里:

    • (?:…)是非捕获组,它是匹配的一部分
    • 1[012]|[1-9]
      表示匹配a)
      1
      后接a
      0
      1
      2
      ,或(
      )b)介于
      1
      9
      之间的一位数字
    • (?::…)
      中的第二个冒号表示将在另一个非捕获组中进行以冒号开头的匹配)
    • [0-5]{2}
      表示匹配两个(
      {2}
      )字符,每个字符的位数介于
      0
      5
      之间
    • /i
      中的
      i
      表示不考虑大小写
    假设现在我们有:

    str3 = "I'm leaving at 9:30 am, so I'll see you at Hotel KingsMen at 10 am."  
    
    我们希望选择“上午10点”而不是“上午9:30”。为此,我们需要额外的假设。例如,我们可以假设时间前面有“at”一词,并且“at”紧跟在酒店名称之后:

    Hotel KingsMen at 10am
    


    我们可以使用一个相当复杂的正则表达式来提取这里的时间,或者我们可以首先在字符串中找到酒店名称及其位置,然后立即查找后面的时间。

    @GaganGami当然可以。您也可以访问以获取额外的提示。对不起。输出在哪里?您使用二进制求反运算符的目的是什么?
    Kingsmen hotel at 10:15 am