Преобразование из строки iso8601. Swift [dубликат]

Если вы хотите, чтобы компилятор автоматически обнаруживал символы, определенные в других файлах, вам нужно заставить программиста разместить эти файлы в предопределенных местах (например, структура пакетов Java определяет структуру папок проекта). Я предпочитаю файлы заголовков. Также вам понадобятся либо источники библиотек, которые вы используете, либо какой-то единый способ поместить информацию, необходимую компилятору в двоичные файлы.

14
задан dlamblin 18 July 2009 в 07:49
поделиться

11 ответов

Если вы точно знаете, какие поля вы получите, вы можете использовать один вызов sscanf () :

  const char * stringToParse = ...  ;  int days, hours, minutes, seconds;  Интервал NSTimeInterval;  if (sscanf (stringToParse, «P% dDT% dH% dM% sS», & amp; days, & amp; hours, & amp; minutes & amp; seconds) == 4) интервал = ((дни * 24 + часы) * 60  + минуты) * 60 + секунды;  иначе;  // обрабатывать ошибку, синтаксический анализ не удалось  

Если какое-либо из полей может быть опущено, вам нужно будет немного умнее в вашем разборе, например:

  const char * stringToParse = ...;  int days = 0, hours = 0, minutes = 0, seconds = 0;  const char * ptr = stringToParse;  while (* ptr) {if (* ptr == 'P' || * ptr == 'T') {ptr ++;  Продолжать;  } значение int, charsRead;  тип char;  if (sscanf (ptr, "% d% c% n", & amp; value, & amp; type & amp; charsRead)! = 2);  // обрабатывать ошибку синтаксического анализа if (type == 'D') days = value;  else if (type == 'H') hours = value;  else if (type == 'M') minutes = value;  else if (type == 'S') seconds = value;  иначе;  // обрабатывать недопустимый тип ptr + = charsRead;  } Интервал NSTimeInterval = ((дни * 24 + часы) * 60 + минуты) * 60 + секунд;   
6
ответ дан Adam Rosenfield 16 August 2018 в 10:22
поделиться
  • 1
    написать небольшой парсер не совсем то, что я имел в виду, когда начал искать легкое решение, но, похоже, нет другого пути. Я думал, что может быть трюк с использованием специальной строки формата с NSDateFormatter, но, похоже, она не работает с временными интервалами. Во всяком случае, я закончил тем, что написал аналогичный парсер. Спасибо всем за помощь. – Zargony 23 July 2009 в 08:18
  • 2
    Одна маленькая вещь, которую нужно иметь в виду с приведенным выше примером кода (да, я понимаю, что это, вероятно, предназначалось для доказательства точки, а не для фактического потребления). Стандарт ISO 8601 позволяет задавать значения продолжительности как дробные значения (то есть 1,5, 0,6 и т. Д.), Которые могут быть разделены символом «.». или ",". – Chuck Wolber 17 April 2012 в 03:54

Уже есть ответы, но я закончил реализацию еще одной версии, используя NSScanner . Эта версия игнорирует год и месяц, так как они не могут быть преобразованы в число секунд.

  static NSTimeInterval timeIntervalFromISO8601Duration (NSString * duration) {NSTimeInterval timeInterval = 0;  NSScanner * scanner = [NSScanner scannerWithString: duration];  Обозначения NSCharacterSet * = [NSCharacterSet characterSetWithCharactersInString: @ "PYMWDTHMS"];  BOOL isScanningTime = NO;  while (! [scanner isAtEnd]) {double scannedNumber = 0;  BOOL didScanNumber = [сканирование scanDouble: & scannedNumber];  NSString * scanned = nil;  if ([сканирование scanCharactersFromSet: указатели вString: & amp; scanned]) {if (didScanNumber) {switch ([отсканированный символAtIndex: 0]) {case 'D': timeInterval + = scannedNumber * 60 * 60 * 24;  ломать;  case 'H': timeInterval + = scannedNumber * 60 * 60;  ломать;  case 'M': if (isScanningTime) {timeInterval + = scannedNumber * 60;  } ломать;  case 'S': timeInterval + = scannedNumber;  ломать;  default: break;  }} if ([scanned containsString: @ "T"]) {isScanningTime = YES;  }}} return timeInterval;  }  
0
ответ дан Barum Rho 16 August 2018 в 10:22
поделиться

Быстрая и грязная реализация

  - (NSInteger) integerFromYoutubeDurationString: (NSString *) duration {if (duration == nil) {return 0;  } NSString * startConst = @ "PT";  NSString * hoursConst = @ "H";  NSString * minutesConst = @ "M";  NSString * secondsConst = @ "S";  NSString * hours = nil;  NSString * minutes = nil;  NSString * seconds = nil;  NSInteger totalSeconds = 0;  NSString * clean = [dлительность компонентовSeparatedByString: startConst] [1];  if ([clean containsString: hoursConst]) {hours = [clean componentsSeparatedByString: hoursConst] [0];  clean = [clean componentsSeparatedByString: hoursConst] [1];  totalSeconds = [hours integerValue] * 3600;  } if ([clean containsString: minutesConst]) {minutes = [clean componentsSeparatedByString: minutesConst] [0];  clean = [clean componentsSeparatedByString: minutesConst] [1];  totalSeconds = totalSeconds + [minutes integerValue] * 60;  } if ([clean containsString: secondsConst]) {seconds = [clean componentsSeparatedByString: secondsConst] [0];  totalSeconds = totalSeconds + [seconds integerValue];  } return totalSeconds;  }  
0
ответ дан dpizzuto 16 August 2018 в 10:22
поделиться

Чистая версия Objective C ...

  NSString * duration = @ "P1DT10H15M49S";  int i = 0, days = 0, hours = 0, minutes = 0, seconds = 0;  while (i & lt; duration.length) {NSString * str = [duration substringWithRange: NSMakeRange (i, duration.length-i)];  я ++;  if ([str hasPrefix: @ "P"] || [str hasPrefix: @ "T"]) продолжить;  NSScanner * sc = [NSScanner scannerWithString: str];  int value = 0;  if ([sc scanInt: & amp; value]) {i + = [sc scanLocation] -1;  str = [duration substringWithRange: NSMakeRange (i, duration.length-i)];  я ++;  if ([str hasPrefix: @ "D"]) days = value;  else if ([str hasPrefix: @ "H"]) hours = value;  else if ([str hasPrefix: @ "M"]) minutes = value;  else if ([str hasPrefix: @ "S"]) seconds = value;  }} NSLog (@ "% @", [NSString stringWithFormat: @ "% d дней,% d часов,% d mins,% d секунд", дней, часов, минут, секунд]);   
10
ответ дан headkaze 16 August 2018 в 10:22
поделиться
  • 1
    Это не подходит для P1M - (дает 1 минуту для этого, вместо этого он должен возвращаться 1 месяц) – Ankit Srivastava 24 February 2014 в 13:12

Реализация Swift2: https://github.com/Igor-Palaguta/YoutubeEngine/blob/swift-2.3/YoutubeEngine/Classes/Parser/NSDateComponents+ISO8601.swift

] Пример: let components = NSDateComponents (ISO8601String: «P1Y2M3DT4H5M6S»)

Тесты: https://github.com/Igor-Palaguta/YoutubeEngine/blob/swift -2.3 / Пример / Тесты / ISO8601DurationTests.swift

Он также корректно обрабатывает случаи «P1M» и «PT1M»

Реализация Swift3: https: // gitub.com/Igor-Palaguta/YoutubeEngine/blob/master/Source/YoutubeEngine/Parser/NSDateComponents%2BISO8601.swift

Пример: let components = dateComponents (ISO8601String: "P1Y2M3DT4H5M6S ")

Тесты: https://github.com/Igor-Palaguta/YoutubeEngine/blob/master/Tests/YoutubeEngineTests/ISO8601DurationTests.swift

Обновление 20.01.2017: добавлена ​​поддержка недель

6
ответ дан Igor Palaguta 16 August 2018 в 10:22
поделиться
  • 1
    Не включает поддержку в течение нескольких недель. Например, P3W3DT20H31M21 не работает. – Doug Smith 19 January 2017 в 16:28
  • 2
    @DougSmith, спасибо за отзывы. Добавлена ​​поддержка недель, теперь вы можете использовать свойство weekOfYear, чтобы получить неделю – Igor Palaguta 20 January 2017 в 01:05
  • 3
    Потрясающие! спасибо – Doug Smith 21 January 2017 в 05:19

слегка изменяющая функция пользователя

Сергей Пекар

  + (NSString *) parseISO8601Time: (NSString *) duration {NSInteger hours = 0;  NSInteger minutes = 0;  NSInteger seconds = 0;  // Получить часть времени из длительности отформатированного ISO 8601 http://en.wikipedia.org/wiki/ISO_8601#Durations if ([duration rangeOfString: @ "T"]. Location == NSNotFound || [dиапазон продолжительностиOfString: @ "P  "] .location == NSNotFound) {NSLog (@" Время не является частью продолжительности отформатированного ISO 8601 ");  return @ "0:00 Ошибка";  } duration = [duration substringFromIndex: [duration rangeOfString: @ "T"]. location];  while ([dлина продолжительности] & gt; 1) {// остается только одна буква после продолжительности синтаксического анализа = [dлительность подстрокиFromIndex: 1];  NSScanner * scanner = [[NSScanner alloc] initWithString: duration];  NSString * durationPart = [[NSString alloc] init];  [сканирование scanCharactersFromSet: [NSCharacterSet characterSetWithCharactersInString: @ "0123456789"] inString: & amp; durationPart];  Диапазон NSRangeOfDurationPart = [dиапазон продолжительностиOfString: durationPart];  if ((rangeOfDurationPart.location + rangeOfDurationPart.length) & gt; duration.length) {NSLog (@ "Время не является частью продолжительности отформатированного ISO 8601");  return @ "0:00 Ошибка";  } duration = [duration substringFromIndex: rangeOfDurationPart.location + rangeOfDurationPart.length];  if ([[duration substringToIndex: 1] isEqualToString: @ "H"]) {hours = [durationPart intValue];  } if ([[duration substringToIndex: 1] isEqualToString: @ "M"]) {minutes = [durationPart intValue];  } if ([[duration substringToIndex: 1] isEqualToString: @ "S"]) {seconds = [durationPart intValue];  }} if (hours! = 0) return [NSString stringWithFormat: @ "% ld:% 02ld:% 02ld", (long) hours, (long) minutes, (long) seconds];  else return [NSString stringWithFormat: @ "% ld:% 02ld", (long) minutes, (long) seconds];  }  
3
ответ дан jose920405 16 August 2018 в 10:22
поделиться
1
ответ дан josliber 16 August 2018 в 10:22
поделиться

Вот быстрая версия 3 примера headkaze: этот формат был наиболее подходящим в моем случае:

  private func parseISO8601Time (iso8601: String) - & gt;  String {let nsISO8601 = NSString (string: iso8601) var days = 0, hours = 0, minutes = 0, seconds = 0 var i = 0 while i & lt;  nsISO8601.length {var str = nsISO8601.substring (с: NSRange (location: i, length: nsISO8601.length - i)) i + = 1, если str.hasPrefix ("P") ||  str.hasPrefix ("T") {продолжить} пусть сканер = сканер (строка: str) значение var = 0, если scanner.scanInt (& amp; value) {i + = scanner.scanLocation - 1 str = nsISO8601.substring (с:  NSRange (location: i, length: nsISO8601.length - i)) i + = 1, если str.hasPrefix ("D") {days = value} else, если str.hasPrefix ("H") {hours = value} else if  str.hasPrefix ("M") {minutes = value} else, если str.hasPrefix ("S") {seconds = value}}}, если days & gt;  0 {часы + = 24 * дней}, если часы & gt;  0 {return String (формат: "% d:% 02d:% 02d", часы, минуты, секунды)} return String (формат: "% d:% 02d", минуты, секунды)}  
1
ответ дан Nikola Jovic 16 August 2018 в 10:22
поделиться

Эта версия анализирует каждую продолжительность без ошибок. Важно: в этой версии используется ARC.

  - (NSString *) parseISO8601Time: (NSString *) duration {NSInteger hours = 0;  NSInteger minutes = 0;  NSInteger seconds = 0;  // Получить часть времени из длительности отформатированного ISO 8601. Http://en.wikipedia.org/wiki/ISO_8601#Durations duration = [duration substringFromIndex: [duration rangeOfString: @ "T"]. Location];  while ([dлина продолжительности] & gt; 1) {// остается только одна буква после продолжительности синтаксического анализа = [dлительность подстрокиFromIndex: 1];  NSScanner * scanner = [[NSScanner alloc] initWithString: duration];  NSString * durationPart = [[NSString alloc] init];  [сканирование scanCharactersFromSet: [NSCharacterSet characterSetWithCharactersInString: @ "0123456789"] inString: & amp; durationPart];  Диапазон NSRangeOfDurationPart = [dиапазон продолжительностиOfString: durationPart];  duration = [duration substringFromIndex: rangeOfDurationPart.location + rangeOfDurationPart.length];  if ([[duration substringToIndex: 1] isEqualToString: @ "H"]) {hours = [durationPart intValue];  } if ([[duration substringToIndex: 1] isEqualToString: @ "M"]) {minutes = [durationPart intValue];  } if ([[duration substringToIndex: 1] isEqualToString: @ "S"]) {seconds = [durationPart intValue];  }} return [NSString stringWithFormat: @ "% 02d:% 02d:% 02d", часы, минуты, секунды];  }  
7
ответ дан Paresh Navadiya 16 August 2018 в 10:22
поделиться

Теперь в Swift !

Управляет годами, месяцами, неделями, днями, часами, секундами и секундами!

   ] func convertFromISO8601Duration (isoValue: AnyObject) - & gt;  Строка?  {var displayString: String?  var hasHitTimeSection = false var isSingular = false, если let isoString = isoValue как?  String {отображаетсяString = String () для val в isoString {if val == "P" {// Не делайте ничего при разборе 'P' continue} else, если val == "T" {// Указываем, что мы имеем дело с  «временной отрезок» длительности ISO8601, а затем продолжить.  hasHitTimeSection = true continue} var tempString = String (), если val & gt; = "0" & ​​amp; & amp; & amp; & amp;  val & lt; = "9" {// Нам нужно знать, является ли значение сингулярным ('1') или нет ('11', '23').  если let safeDisplayedString = displayString as String!  где count (displayString!) & gt;  0 & amp; & amp;  val == "1" {let lastIndex = count (safeDisplayedString) - 1 let lastChar = safeDisplayedString [advance (safeDisplayedString.startIndex, lastIndex)] // проверяет, является ли текущий последний символ в отображаемой строке пробелом ("").  Если это так, то мы скажем, что это сингулярно, пока не будет доказано обратное.  if lastChar == "" {isSingular = true} else {isSingular = false}} else if val == "1" {// если мы просто имеем дело с '1', тогда мы скажем, что это единственное, пока не будет доказано обратное.  isSingular = true} else {// ... в противном случае это множественная продолжительность.  isSingular = false} tempString + = "\ (val)" отображаетсяString!  + = tempString} else {// обрабатывает текст типа продолжительности.  Обязательно используйте Months & amp;  Минуты правильно.  switch val {case "Y", "y": if isSingular {tempString + = "Year"} else {tempString + = "Years"} break case "M", "m": if hasHitTimeSection {if isSingular {tempString + =  "Minute"} else {tempString + = "Minutes"}} else {if isSingular {tempString + = "Month"} else {tempString + = "Months"}} break case "W", "w": if isSingular {tempString  + = "Неделя"} else {tempString + = "Weeks"} break case "D", "d": if isSingular {tempString + = "Day"} else {tempString + = "Days"} break case "H"  "h": if isSingular {tempString + = "Hour"} else {tempString + = "Hours"} break case "S", "s": if isSingular {tempString + = "Second"} else {tempString + = "Секунды  "} break default: break} // сбросить наш особый флаг, так как мы начинаем новую продолжительность.  isSingular = false отображаетсяString!  + = tempString}}} return displayString}  
0
ответ дан Sakiboy 16 August 2018 в 10:22
поделиться

Я просмотрел эту статью в Википедии для ссылки на то, как работает ISO-8601. Я не эксперт по какао, но я уверен, что если вы сможете разобрать эту строку и извлечь компонент час, минуту, секунду, день и т. Д., То получить его в NSTimeInterval должно быть легко. Сложная часть разбирает его. Я бы сделал это примерно так:

Сначала разделите строку на две отдельные строки: одну, представляющую дни, и одну, представляющую время. NSString имеет компонент метода экземпляраSeparatedByString: NSString, который возвращает NSArray подстрок вашего исходного NSString, разделенных параметром, который вы передаете. Он будет выглядеть примерно так:

  NSString * iso8601 = / * Однако  вы получаете свою строку в * / NSArray * iso8601Parts = [iso8601 componentsSeparatedByString: @ "T"];   

Затем выполните поиск первого элемента iso8601Parts для каждого из возможных индикаторов продолжительности дня (Y, M, W и D). Когда вы найдете его, возьмите все предыдущие цифры (и, возможно, десятичную точку), отбросьте их к плавающей точке и сохраните их где-нибудь. Помните, что если бы существовал только элемент времени, то iso8601Parts [0] будет пустой строкой.

Затем сделайте то же самое, ищите временные части во втором элементе iso8601Parts для возможных индикаторов времени (H , МИЗ). Помните, что если бы существовал только компонент дня (т. Е. В исходной строке не было символа «T»), то iso8601Parts будет иметь длину только один, а попытка доступа к второму элементу вызовет исключение из-за пределов .

NSTimeInterval - это просто длительное хранение нескольких секунд, поэтому конвертируйте отдельные фрагменты, которые вы вытащили за секунды, добавьте их вместе, сохраните их в своем NSTimeInterval, и вы настроены.

Извините, я знаю, что вы попросили «простой» способ сделать это, но, основываясь на моем (по общему признанию) поиске и знании API, это самый простой способ сделать это.

0
ответ дан Warren Pena 16 August 2018 в 10:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: