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)
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"
在这里:
- (?:…)是非捕获组,它是匹配的一部分
表示匹配a)1[012]|[1-9]
后接a1
、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