Смешайте группы, соответствующие регулярному выражению

avatar
Omar Taher
8 августа 2021 в 19:35
51
2
0

Если у меня есть ввод, такой как SuMoTu 11:00AM - 1:00PM, возможно ли сгенерировать Su 11:00AM - 1:00PM, Mo 11:00AM - 1:00PM, Tu 11:00AM - 1:00PM с использованием только регулярного выражения без использования циклов?

Я хочу смешать 11:00AM - 1:00PM со всеми связанными днями SuMoTu.

Конечно, дни не всегда будут состоять из 3 дней. Он будет варьироваться от 1 дня до 5 дней. Кроме того, дни будут представлены только двумя символами. Для времени это всегда будет один временной диапазон.

Источник
James K. Lowden
8 августа 2021 в 19:44
1

Да, возможно, но любой ответ, который вы получите, скорее всего, будет слишком конкретным. Если вы предоставите больше примеров входных данных, вы можете получить лучший, более общий ответ. Всегда ли есть 3 дня с 2 письмами каждый? Всегда один временной диапазон?

Omar Taher
8 августа 2021 в 19:48
1

@JamesK.Lowden Спасибо за ваш комментарий. Я отредактировал вопрос.

Ответы (2)

avatar
vsemozhebuty
8 августа 2021 в 21:29
1

Вы можете попробовать использовать предварительный просмотр с группами захвата и без захвата. Вот пример на JavaScript:

const re = /([A-Z][a-z])(?=(?:[A-Z][a-z])+ (\d\d?:\d\d(?:AM|PM) - \d\d?:\d\d(?:AM|PM)))/g;
const replacement = '$1 $2, ';

console.log('Su 11:00AM - 1:00PM'.replace(re, replacement));
console.log('SuMo 11:00AM - 1:00PM'.replace(re, replacement));
console.log('SuMoTu 11:00AM - 1:00PM'.replace(re, replacement));
console.log('SuMoTuWe 11:00AM - 1:00PM'.replace(re, replacement));
console.log('SuMoTuWeTh 11:00AM - 1:00PM'.replace(re, replacement));
avatar
James K. Lowden
8 августа 2021 в 20:42
1

без использования петель

Я думаю, что ответ "Нет" по теоретическим причинам. Регулярные выражения решают, что делать по мере продвижения по входной строке. Что вы хотите сделать, так это сопоставить часть строки (Su), напечатать ее, затем перейти к пробелу, взять оставшуюся часть строки, напечатать ее, а затем вернуться к последнему следующему 2-буквенному дню и повторить. Для этого нет регулярного выражения. Для него может быть какое-то расширенное регулярное выражение, но это все равно будет цикл.

Однако можно обойтись и очень маленьким циклом:

$ echo SuMoTu 11:00AM - 1:00PM | 
  awk '{ time = $2 " - " $4; 
         while(/^[SMTWTFS]/) { 
             day = substr($1, 1, 2); 
             $1 = substr($1, 3, length($1) - 2); 
             print day, time 
         } 
       }'
Su 11:00AM - 1:00PM
Mo 11:00AM - 1:00PM
Tu 11:00AM - 1:00PM

Объяснение:

awk разбивает входные данные на строки, разделенные пробелами, и нумерует их $1, $2 и т. д. Если входная строка начинается с заглавной буквы, обозначающей день, удалите первые две буквы и распечатайте их вместе с компонентами времени (захваченными в $2 и $4).

Этот цикл "небольшой" в том смысле, что каждая входная строка читается один раз и сканируется N раз, где N — количество дней в первой строке.

Я сомневаюсь, что вы найдете что-то более быстрое для этой задачи, чем awk без использования скомпилированного языка. Если вы не обрабатываете миллионы строк в очень ограниченной по времени ситуации, вам это тоже не понадобится. Моя маленькая машина обработала 1 миллион строк за 3 секунды.