2016-11-03 4 views
4

У меня есть строка, например. 02112016. Я хочу сделать datetime из этой строки.Regex не работает в первый раз

Я пробовал:

s = "02112016" 
s.sub(/(\d{2})(\d{2})(\d{4})/, "#{$1}-#{$2}-#{$3}") 

Но есть проблема. Он возвращает "--".

Если я попробую это s.sub(/(\d{2})(\d{2})(\d{4})/, "#{$1}-#{$2}-#{$3}"), он работает: "02-11-2016". Теперь я могу использовать метод to_datetime.

Но почему s.sub(/(\d{2})(\d{2})(\d{4})/, "#{$1}-#{$2}-#{$3}") не работает в первый раз?

ответ

4

Это действительно простое изменение здесь. $1 и друзья назначаются только после матч проходит успешно, а не во время матча. Если вы хотите использовать непосредственные значения, сделайте следующее:

s = "02112016" 
s.sub(/(\d{2})(\d{2})(\d{4})/, '\1-\2-\3') 

# => "02-11-2016" 

Здесь \1 соответствует тому, что будет назначен $1. Это особенно важно, если вы используете gsub, так как $1 имеет тенденцию быть последним, только если \1 оценивается для каждого матча индивидуально.

2

То, что происходит в первый раз вы запускали его, $1, $2 и $3 пустые

Вы по существу заменял число пустых строк.

Так что, если мы делаем

s = "02112016" 

p $1 #=> nil 
p $2 #=> nil 
p $3 #=> nil 

s.sub(/(\d{2})(\d{2})(\d{4})/, "#{$1}-#{$2}-#{$3}") #=> "--" 

p $1 #=> "02" 
p $2 #=> "11" 
p $3 #=> "2016" 

s.sub(/(\d{2})(\d{2})(\d{4})/, "#{$1}-#{$2}-#{$3}") #=> "02-11-2016" 

Вот почему он работает во второй раз.

Поскольку строка всегда имеет одинаковую длину, вы можете использовать метод [], чтобы разбить его.

s = "#{s[0..1]}-#{s[2..3]}-#{s[4..-1]}" 

Это вернет желаемый результат

"02-11-2016" 
3

Я предпочитаю следующее.

r =/
    \d{2}  # match two digits 
    (?=\d{4}) # match four digits in a positive lookahead 
    /x  # free-spacing regex definition mode 

, который так же, как

r = /\d{2}(?=\d{4})/ 

для использования с String#gsub:

s.gsub(r) { |s| "#{s}-" } 

Попробуйте:

"02112016".gsub(r) { |s| "#{s}-" } 
    #=> "02-11-2016"