Как я могу удалить ненужные символы из строк, похожих на дату, в массиве?

#arrays #ruby #string #date

#массивы #ruby #строка #Дата

Вопрос:

У меня есть массив с несколькими датами и временем:

 [ "24/Oct/2014:13:43:15 -0600",
  "25/Oct/2014:14:47:25 -0600",
  "24/Oct/2014:13:46:15 -0600" ]
  

Я пытался получить.

 ["24/Oct/2014", "25/Oct/2014", "24/Oct/2014"]
  

Я пытался использовать gsub для замены того, что не нужно, пробелом, но это только удалило двоеточия. Как я мог бы это удалить?

Ответ №1:

Множество альтернатив со строками

Существует множество способов манипулировать строками даты как строковыми объектами. В вашем случае два таких параметра включают строку#partition и строку#match. Например:

 dates = [
  "24/Oct/2014:13:43:15 -0600",
  "25/Oct/2014:14:47:25 -0600",
  "24/Oct/2014:13:46:15 -0600"
]

dates.map { |date| date.match(/A[^:] /).to_s }
dates.map { |date| date.partition(?:)[0] }
  

Оба метода вернут массив строк, подобных следующему:

 #=> ["24/Oct/2014", "25/Oct/2014", "24/Oct/2014"]
  

Соображения

Основная проблема при работе с такими датами в качестве строковых объектов заключается в том, что вы предполагаете, что строковое представление всегда будет одинаковым. Если вы знаете свои данные, это нормально, но часто лучше рассматривать даты как даты. Например, вы можете использовать Date#parse, с датой#strftime или без нее, для автоматической обработки общих представлений следующим образом:

 require 'date'

# Remove #to_s if you want to return actual Date objects for
# further processing, rather than an array of strings.
dates.map { |date| Date.parse(date).to_s }
#=> ["2016-10-24", "2016-10-25", "2016-10-24"]

# This will only return strings, but that's what you originally
# asked for.
dates.map { |date| Date.parse(date).strftime '%d/%b/%Y' }
#=> ["24/Oct/2016", "25/Oct/2016", "24/Oct/2016"]
  

Библиотеки Date и DateTime также содержат другие анализаторы. Конечно, если вы используете нестандартный формат ввода, вы можете использовать Date#strptime с пользовательским шаблоном.

Суть здесь в том, что обработка строковых объектов работает, но обычно лучше иметь дело с датами как объектами Date или DateTime, чтобы избежать крайних случаев, проверять входные данные и вызывать исключения, такие как:

 dates.map { |date| Date.rfc2822 date }
  

Ошибка аргумента: недопустимая дата

при необходимости. Вы обязательно должны использовать основные возможности, подобные этому, когда это возможно.

Ответ №2:

 arr = ["24/Oct/2014:13:43:15 -0600",
       "05/Oct/2014:14:47:25 -0600",
       "24/Oct/2014:13:46:15 -0600"]
  

Если вы уверены, что формат строк даты будет правильным и будет представлять действительные даты, вы можете просто написать

 arr.map { |s| s[0,11] }
  #=> ["24/Oct/2014", "05/Oct/2014", "24/Oct/2014"]
  

С другой стороны, если вы хотите проверить правильность строк даты, вы можете преобразовать каждую строку даты в объект date, а затем преобразовать этот объект в желаемый формат строки. Таким образом, будет вызвано исключение, если строка даты недопустима.

 require 'date'

arr.map { |s| DateTime.strptime(s, '%d/%b/%Y:%H:%M:%S %z').strftime('%d/%b/%Y') }
  #=> ["24/Oct/2014", "05/Oct/2014", "24/Oct/2014"] 
  

Для этого используются методы DateTime::strptime и DateTime#strftime. Строки формата даты описаны в документе для strftime .

Предположим

 arr = ["42/Oct/2014:13:43:15 -0600"]
  

затем

 arr.map { |s| DateTime.strptime(s, '%d/%b/%Y:%H:%M:%S %z').strftime('%d/%b/%Y') }
  #=> ArgumentError: invalid date
  

Вы могли бы вместо этого использовать DateTime::parse вместо strptime преобразования строк даты в Date объекты, но он довольно слаб при определении недопустимых дат. Например:

 DateTime.parse "123456/01-02abc"
  #=> #<DateTime: 123456-01-02T00:00:00 00:00 ((46812439j,0s,0n),...
DateTime.parse "-7/8"
  #=> #<DateTime: 2016-07-08T00:00:00 00:00 ((2457578j,0s,0n),...
DateTime.parse "He demanded 1/2 of the pie"
  #=> #<DateTime: 2016-01-02T00:00:00 00:00 ((2457390j,0s,0n),...
  

Ответ №3:

Просто разделите на : и выбросьте остальное:

 times = [ "24/Oct/2014:13:43:15 -0600", "25/Oct/2014:14:47:25 -0600", "24/Oct/2014:13:46:15 -0600" ]

times.map do |time|
  time.split(':').first
end

# => ["24/Oct/2014", "25/Oct/2014", "24/Oct/2014"]
  

Если вы хотите сделать это на месте и изменить свой массив, используйте map! .

Комментарии:

1. является ли вызов ruby array times отличной идеей?

2. Это массив времен, но вы можете называть его практически как угодно, если это не противоречит зарезервированному ключевому слову. times не является одним из них.