Один из способов сделать это - поддержка блоков RegexKitLites:
NSString *string = @"Mon-Wed 930-1700 Thu 900-1700 Fri 930-1700\nMon-Wed 930-1700 Thu 900-1700 Fri 930-1700 Sat 900-1200, Home Lending Sat 900-1600\nMon-Thu 900-1600, Fri 900-1700";
NSString *replaced = [string stringByReplacingOccurrencesOfRegex:@"(?<=[[:Pattern_Syntax:][:White_Space:]]|\\A)(\\d{1,2})(\\d{2,2})(?=[[:Pattern_Syntax:][:White_Space:]]|\\z)" usingBlock:^NSString *(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop) {
NSInteger hour = [capturedStrings[1] integerValue];
NSString *amOrPMString = @"am";
if(hour >= 12) { amOrPMString = @"pm"; if(hour > 12) { hour -= 12; } }
return([NSString stringWithFormat:@"%d:%@%@", hour, capturedStrings[2], amOrPMString]);
}];
NSLog(@"Replaced:\n%@", replaced);
При запуске распечатывается следующее:
2010-07-10 17:42:10.650 RegexKitLite[26086:a0f] Replaced:
Mon-Wed 9:30am-5:00pm Thu 9:00am-5:00pm Fri 9:30am-5:00pm
Mon-Wed 9:30am-5:00pm Thu 9:00am-5:00pm Fri 9:30am-5:00pm Sat 9:00am-12:00pm, Home Lending Sat 9:00am-4:00pm
Mon-Thu 9:00am-4:00pm, Fri 9:00am-5:00pm
РЕДАКТИРОВАТЬ 2010/07/11 - Добавить информацию по запросу OP.
Объяснение регулярного выражения, использованного в примере, следующее (с разбивкой на четыре наиболее логичных блока)
1: (?<=[[:Pattern_Syntax:][:White_Space:]]|\A)
2: (\d{1,2})
3: (\d{2,2})
4: (?=[[:Pattern_Syntax:][:White_Space:]]|\z)
Часть 1
Последовательность (?<= ... )
означает «утверждение с предварительным просмотром», или в прозе, это примерно переводится во что-то вроде «Если следующая часть регулярного выражения (в данном случае, # 2),тогда текст перед # 2 должен соответствовать регулярному выражению, заключенному в эти круглые скобки ".
Регулярное выражение" заключенному в эти круглые скобки "в данном случае равно [[:Pattern_Syntax:][:White_Space:]]|\A
.Это регулярное выражение в грубой прозе говорит: «Сопоставьте любой символ в наборе символов со свойством Unicode Pattern_Syntax или White_Space или \A
, что означает Match at the beginning of the input. Differs from ^ in that \A will not match after a new-line within the input.
.Символы Pattern_Syntax
или White_Space
- это такие символы, как '' (пробел), '\ t' (табуляция), новые строки и т. Д. И т. Д. Pattern_Syntax
такие символы, как '-', ',','% 'и т. д.
Части 2 и 3
Эти части довольно очевидны.\d
соответствует «цифровому» символу, например «0» .. «9», а {x,y}
означает «Совпадение не менее x
, но не более y
раз».
Часть 4
Часть 4, по сути, идентична части первой, за исключением того, что в ней используется «прогнозное утверждение» в форме (?=
, и, как мы надеемся, значение должно быть очевидно из контекста объяснения вчасть 1. Другое отличие заключается в использовании \z
, что означает «Сопоставить, если текущая позиция находится в конце ввода».
Зачем нужны \A
и \z
?В случае, если время является самым первым в строке или самым последним в строке, так как набор символов []
для сопоставления не содержит "или нет символа, если в начале или конце сопоставляемого текста».Например, пример строки OP заканчивается на ..., Fri 900-1700
.Без |\z
регулярное выражение не соответствовало бы последнему 1700
.
Зачем нужны части 1 и 4?Их может не быть, в зависимости от точного формата текстовой строки для сопоставления.Поскольку я не могу много сказать о формате входной строки, я попытался сделать ее «достаточно надежной» и терпимой к широкому диапазону разумных входных данных.Определенно есть несколько способов сделать это.
Что делает Блок
Блок ^{}
вызывается каждый раз, когда сопоставляется регулярное выражение.Детали о том, что было найдено, передаются в качестве аргументов в блоки.Затем блок возвращает новую строку, которая используется для замены всего текста, который был сопоставлен с регулярным выражением.Этот процесс повторяется до тех пор, пока в строке не останется совпадений с регулярным выражением.
Для ясности, исходная строка только "совпадает один раз".Например, данное регулярное выражение по существу соответствует любому «числу» в форме «NNN» или «NNNN».Для каждого совпадения вызывается блок, а затем поиск следующего совпадения в исходной строке начинается с самого следующего символа после последнего совпадения.Он не может «возвращаться» или «начинать заново».
Исходная строка не изменяется никоим образом.Вместо этого создается совершенно новая строка.Он создается по частям из «текста между совпадениями» и строк замены, возвращаемых Блоком.Когда все замены завершены, возвращается строка.
РЕДАКТИРОВАТЬ 2010/07/12 - добавить дополнительную информацию для каждого запроса OP (дополнительного).
Q Если бы я был более уверен в согласованности входного формата (такого как Day-DaySpaceTime ИЛИ DaySpaceTime), мог бы я просто получить какое-нибудь регулярное выражение, подобное этому?(\ S | -) (\ д {1,2}) (\ d {2,2}) (;? | \ s | -?). * +1066 *
A Если бы вы были более уверены в формате ввода, регулярное выражение определенно можно было бы изменить.Например, если вы были «абсолютно уверены», что ввод всегда будет иметь вид nNNN-nNNN
(где нижний регистр n
представляет «необязательную цифру», как в 900-1730
против 1100-1915
)для «времен» код может быть изменен на что-то вроде:
NSString *string = @"Mon-Wed 930-1700 Thu 900-1700 Fri 930-1700\nMon-Wed 930-1700 Thu 900-1700 Fri 930-1700 Sat 900-1200, Home Lending Sat 900-1600\nMon-Thu 900-1600, Fri 900-1700";
NSString *replaced = [string stringByReplacingOccurrencesOfRegex:@"\\b(\\d{1,2})(\\d{2,2})\\-(\\d{1,2})(\\d{2,2})\\b" usingBlock:^NSString *(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop) {
NSInteger firstHour = [capturedStrings[1] integerValue], secondHour = [capturedStrings[3] integerValue];
NSString *firstAMorPMString = @"am", *secondAMorPMString = @"am";
if(firstHour >= 12) { firstAMorPMString = @"pm"; if(firstHour > 12) { firstHour -= 12; } }
if(secondHour >= 12) { secondAMorPMString = @"pm"; if(secondHour > 12) { secondHour -= 12; } }
if(firstHour == 0) { firstHour = 12; }
if(secondHour == 0) { secondHour = 12; }
return([NSString stringWithFormat:@"%d:%@%@-%d:%@%@", firstHour, capturedStrings[2], firstAMorPMString, secondHour, capturedStrings[4], secondAMorPMString]);
}];
NSLog(@"Replaced:\n%@", replaced);
В этом примере оба «раза» обрабатываются как один фрагмент.\b
, присутствующий в начале и в конце регулярного выражения, означает Match if the current position is a word boundary
.Это предотвращает совпадение с чем-то вроде abc123-456def
.Это более простая форма более сложных элементов [[:Pattern_Syntax:][:White_Space:]]
в исходном примере, но это не обязательно означает одно и то же (хотя в большинстве случаев это довольно близко).
Еще одно преимуществосопоставляя оба раза как один фрагмент, это уменьшает количество потенциальных «ложных совпадений», которые могут произойти, если сопоставить их только один раз. Например, в первом примере «комментарий» из «Home econ 101» будет превращен в «Home»econ 1:01 ", что, вероятно, не то, что вам нужно. :)
Я также изменил пример так, чтобы" военное 24-часовое время "из" 000 "означало" 12:00 утра ", поэтомупредположение, что анализируемые значения времени всегда имеют 24-часовой формат военного времени.
Q Также (? <= ...) выглядит за синтаксической частью RegexKitLite или это стандартregex? </p>
A Это часть синтаксиса regex, принятого библиотекой ICU (именно это RegexKitLite использует для фактического сопоставления регулярных выражений). Стенд отсутствуетСинтаксис регулярного выражения ard "per se, хотя" большинство "обработчиков регулярных выражений принимает и (?<=...)
, и (?=...)
.
Q Извините, в вашем регулярном выражении у вас было четыре набораof () означает ли это, что есть capturedStrings [0], capturedStrings [1], capturedStrings [2], capturedStrings [3]?
A (?<=...)
и (?=...)
шаблоны - это то, что известно как «утверждения нулевой ширины».Они на самом деле не вносят вклад в текст, «захваченный» регулярным выражением, но должны соответствовать заданному тексту, чтобы общее регулярное выражение «соответствовало».Различие между словами «захваченный» и «совпадение» в предыдущем предложении состоит в том, что «захваченный» потребляет совпадающую часть ввода, тогда как «сопоставленный» - нет.Это позволяет вам создавать регулярные выражения, такие как (\d+)(?=,)
, что означает «Сопоставить и« захватить »одно или несколько чисел, за которыми должно следовать«, », но не захватывать запятую».Забегание вперед и оглядывание назад - определенно продвинутые, неопытные возможности регулярных выражений, которые трудно полностью объяснить в таком коротком посте, как этот.
Однако следует особо отметить, что ни (?<=...)
, ни(?=...)
считается "захватом", в отличие от (\d{1,2})(\d{2,2})
.Полное регулярное выражение из исходного примера содержит только два захвата, хотя всего в скобках четыре группы.