(Ruby)regex可选匹配项
我正在编写一个Rack应用程序来拆分以某些前缀结尾的主机名 例如,主机名(和端口)(Ruby)regex可选匹配项,ruby,regex,Ruby,Regex,我正在编写一个Rack应用程序来拆分以某些前缀结尾的主机名 例如,主机名(和端口)hello.world.lvh.me:3000需要拆分为令牌hello.world、.lvh.me和:3000。此外,前缀(hello.world)、后缀(.lvh.me)和端口(:3000)都是可选的 到目前为止,我有一个(Ruby)正则表达式,看起来像/(.*)(\.lvh\.me)(\:\d+)/ 这将成功地将主机名分解为多个组件,但当一个或多个可选组件丢失时,主机名会下降,例如hello.world:300
hello.world.lvh.me:3000
需要拆分为令牌hello.world
、.lvh.me
和:3000
。此外,前缀(hello.world
)、后缀(.lvh.me
)和端口(:3000
)都是可选的
到目前为止,我有一个(Ruby)正则表达式,看起来像/(.*)(\.lvh\.me)(\:\d+)/
这将成功地将主机名分解为多个组件,但当一个或多个可选组件丢失时,主机名会下降,例如hello.world:3000
或lvh.me:3000
甚至是普通的hello.world
我尝试向每个组添加?
,使它们成为可选的(/(.*)(\.lvh\.me)(\:(\d+)/
),但这总是以第一个组((.*)
)结束,捕获整个字符串并停在那里
我的直觉是,这是一个可以用lookaround解决的问题,但我承认这对我来说是一个全新的regex领域。你可以尝试以下模式:
\A(?=[^:])(.+?)??((?:\.|\A)lvh\.me)?(:[0-9]+)?\z
前瞻(?=[^:])
检查是否至少有一个字符不是:
(换句话说,不仅仅是端口)。这意味着至少存在hello.word
或lvh.me
第一组是可选的且非贪婪的?
,这意味着它仅在需要时匹配
\A
和\z
是字符串开头和结尾的锚点(当^
和$
用于行时)
请注意,字符类\d
匹配Ruby中的所有unicode数字,但在本例中,您只需要ascii数字。最好使用[0-9]
还要注意的是,\A(?=[^:])((?>[^l:\n.]+\Bl\l(?!vh\.me\b))*((?:\.\A)lvh\.me)(:[0-9]+)?\z
可能更有效
试试^(.*?)(\.?lvh\.me)?(\:\d+)$
我补充说:
- 将
发送到使?
非贪婪的第一组*
将其锚定到起点和终点^,$
- a
到?
lvh之前的\.
,因为您希望匹配.
而不是lvh.me:3000
。lvh.me:3000
str = 'hello.world.lvh.me:3000'
tokens = str.split /[.:]/
port = tokens.last =~ /\A\d+\z/ ? ?: + tokens.pop : ''
domain = sprintf '.%s.%s', *tokens.pop(2)
prefix = tokens.join ?.
在某些情况下,您当然需要检查空字符串,但它似乎比纯正则表达式解决方案更直接和/或更灵活。无论如何,我发现它更可读。如果您确实需要一个正则表达式,我相信其他答案中的一个会帮助您解决问题。您可以尝试拆分,而不是使用正则表达式阿奇
irb(main):012:0> "hello.world.lvh.me:3000".split(/\.(?=[^.:]+\.[^:.]+(?::\d+)?$)|:/)
=> ["hello.world", "lvh.me", "3000"]
irb(main):013:0> "hello.world:3000".split(/\.(?=[^.:]+\.[^:.]+(?::\d+)?$)|:/)
=> ["hello.world", "3000"]
irb(main):014:0> "lvh.me:3000".split(/\.(?=[^.:]+\.[^:.]+(?::\d+)?$)|:/)
=> ["lvh.me", "3000"]
irb(main):015:0> "hello.world".split(/\.(?=[^.:]+\.[^:.]+(?::\d+)?$)|:/)
=> ["hello.world"]
irb(main):016:0> "hello.world.lvh.me".split(/\.(?=[^.:]+\.[^:.]+(?::\d+)?$)|:/)
=> ["hello.world", "lvh.me"]
听着,妈妈,没有正则表达式
def split_up(str)
str.sub(':','.:')
.split('.')
.each_slice(2)
.map { |arr| arr.join('.') }
end
split_up("hello.world.lvh.me:3000") #=> ["hello.world", "lvh.me", ":3000"]
split_up("hello.world:3000") #=> ["hello.world", ":3000"]
split_up("hello.world.lvh.me") #=> ["hello.world", "lvh.me"]
split_up("hello.world") #=> ["hello.world"]
split_up("") #=> []
步骤:
str1 = "hello.world.lvh.me:3000" #=> "hello.world.lvh.me:3000"
str2 = str1.sub(':','.:') #=> "hello.world.lvh.me.:3000"
arr = str2.split('.') #=> ["hello", "world", "lvh", "me", ":3000"]
enum = arr.each_slice(2) #=> #<Enumerator: ["hello", "world", "lvh",
# "me", ":3000"]:each_slice(2)>
enum.to_a #=> [["hello", "world"], ["lvh", "me"],
# [":3000"]]
enum.map { |arr| arr.join('.') } #=> ["hello.world", "lvh.me", ":3000"]
str1=“hello.world.lvh.me:3000”#=>“hello.world.lvh.me:3000”
str2=str1.sub(“:”,“.:”)#=>“hello.world.lvh.me.:3000”
arr=str2.split('.')#=>[“你好”,“世界”,“lvh”,“我”,“3000”]
enum=arr.each_切片(2)#=>#
enum.to_a#=>[“你好”,“世界”],[“lvh”,“我”],
# [":3000"]]
enum.map{| arr | arr.join('.')}#=>[“hello.world”,“lvh.me”,“:3000”]
差不多了,但是有了lvh.me:3000
,lvh.me
被第一组而不是它自己的组捕获了。喜欢它!我今天从你的回答中学到了一些新东西。提醒一下\A
和\z
与^
和$
相比可能有用,这是一个非常常见的混淆点Ruby的正则表达式。尽管@casimir的答案更为可靠,但我接受了这个答案,因为它足以满足我的目的,并且是我最终使用的。基本上,我不需要正则表达式来关心是否缺少任何组,只要每个组都与它的设计相匹配,而不需要其他任何东西。你确定要^
和吗>$
而不是\A
和\z
?在这种情况下可能没有什么区别,但好习惯就是好习惯。