Входной файл представляет собой минимизированный файл css:
.class{margin:0px}.class1,.class2{margin 0px}@media{.class{color:blue}.class1,.class2{color:red}}@media{.classA.classB,.classC{margin:0px}}@media{.classD,.classE{color:blue}.class1,.class2{color:red}}@media only screen and (min-width: 1441px){.classX{color:blue}}@media only screen and (min-width: 1441px){.class{color:blue}.class1,.class2{color:red}}@media only screen and (min-width: 1441px){.classA.classB,.classC{margin:0px}}@media only screen and (inverted-colors){.classD,.classE{color:blue}.class1,.class2{color:red}.classV{color:red}.classR{color:red}.classU{color:red}.classS{color:red}.classT{color:red}}.classNew{margin: 10px}
Ожидаемый результат:
.class{margin:0px}
.class1,.class2{margin 0px}
@media{.class{color:blue}.class1,.class2{color:red}}
@media{.classA.classB,.classC{margin:0px}}
@media{.classD,.classE{color:blue}.class1,.class2{color:red}}
@media only screen and (min-width: 1441px){.classX(color:blue}}
@media only screen and (min-width: 1441px){.class{color:blue}.class1,.class2{color:red}}
@media only screen and (min-width: 1441px){.classA.classB,.classC{margin:0px}}
@media only screen and (inverted-colors){.classD,.classE{color:blue}.class1,.class2{color:red}.classV{color:red}.classR{color:red}.classU{color:red}.classS{color:red}.classT{color:red}}
.classNew{margin: 10px}
Когда я использую это:
awk '{gsub(/\t?}/, "}\n"); print}'
Это дает следующий результат, который не соответствует ожидаемому результату выше:
.class{margin:0px}
.class1,.class2{margin 0px}
@media{.class{color:blue}
.class1,.class2{color:red}
}
@media{.classA.classB,.classC{margin:0px}
}
@media{.classD,.classE{color:blue}
.class1,.class2{color:red}
}
@media only screen and (min-width: 1441px){.classX(color:blue}
}
@media only screen and (min-width: 1441px){.class{color:blue}
.class1,.class2{color:red}
}
@media only screen and (min-width: 1441px){.classA.classB,.classC{margin:0px}
}
@media only screen and (inverted-colors){.classD,.classE{color:blue}
.class1,.class2{color:red}
.classV{color:red}
.classR{color:red}
.classU{color:red}
.classS{color:red}
.classT{color:red}
}
.classNew{margin: 10px}
Вот моя идея получить ожидаемый результат:
найти {
тогда
после этого проверьте, является ли следующий символ } или {
если }
тогда
добавить новую строку после }
если {
после этого проверьте, является ли следующий символ }}
если }}
тогда
добавить новую строку после }}
пройтись по входному файлу
Это может помочь: Есть ли приложение для автоматического форматирования файлов CSS?
Использование GNU sed
$ sed -E 's/[^}]*}}?([^}]*}})?/&\n/g' input_file
.class{margin:0px}
.class1,.class2{margin 0px}
@media{.class{color:blue}.class1,.class2{color:red}}
@media{.classA.classB,.classC{margin:0px}}
@media{.classD,.classE{color:blue}.class1,.class2{color:red}}
спасибо .. это не работает для большого количества классов или большого файла CSS.
например: экран только @media и (минимальная ширина: 1441px){.classX(цвет:синий}}экран только @media и (min-width: 1441px){.class{color:blue}.class1,.class2{ color:red}}@media only screen and (min-width: 1441px){.classA.classB,.classC{margin:0px}}@media only screen and (inverted-colors){.classD,.classE{color: синий}.class1,.class2{цвет:красный}.classV{cцвет:красный}.classR{цветили:красный}.classU{цвет:красный}.classS{цвет:red}.classT {цвет: красный}}.classNew{поле: 10px}
@SharadShrestha Каков ожидаемый результат для образца? Кажется, это работает с моей стороны, хотя фигурная скобка неуместна
Я обновил входной файл и ожидаемый результат.
двухэтапная awk
процедура
У меня есть процедура, которая работает для вашего примера, но мне пришлось заново интерпретировать правила, и, возможно, она может не работать для каждого случая, который вы хотите обработать, если мои правила неверны (извините, если это так).
интерпретация
Процесс, к которому я стремился:
Если первый открытый блок стиля
{
в строке закрывается (}
) до открытия другого, новая строка начинается сразу после закрытия этого блока.Правило
@media
может быть только в начале строки.для блока, содержащего другие блоки и, таким образом, заканчивающегося на
}}
, новая строка всегда следует за двойным замыканием.
обзор подхода
Процедура использует две процедуры awk
, первая получает входные данные из файла данных, а вторая принимает свои входные данные из выходных данных первой. Сначала я объясню их работу по отдельности, а затем объясню комбинированную процедуру, объединенную с помощью конвейера.
первый неловкий шаг
Этот первый шаг awk
изменяет строку ввода, чтобы учесть правило 3 выше (что }}
может быть только в конце строки). Это достигается путем установки разделителя полей awk
на двойное закрытие с помощью FS = "}}"
. Цикл используется для печати каждого поля (за которым следует }}
, которое в противном случае теряется), в результате чего awk
разделяет поля на свои собственные строки с разделителем выходных записей по умолчанию ORS
(новая строка):
awk 'BEGIN{FS = "}}"} {for(i=1;i<NF;i++) print $i"}}"; print $NF}' mini.css
Этот первый awk
шаг приводит к следующему результату (его не нужно сохранять в файл, так как он будет «перенаправлен» во вторую awk
процедуру позже):
.class{margin:0px}.class1,.class2{margin 0px}@media{.class{color:blue}.class1,.class2{color:red}}
@media{.classA.classB,.classC{margin:0px}}
@media{.classD,.classE{color:blue}.class1,.class2{color:red}}
@media only screen and (min-width: 1441px){.classX(color:blue}}
@media only screen and (min-width: 1441px){.class{color:blue}.class1,.class2{color:red}}
@media only screen and (min-width: 1441px){.classA.classB,.classC{margin:0px}}
@media only screen and (inverted-colors){.classD,.classE{color:blue}.class1,.class2{color:red}.classV{color:red}.classR{color:red}.classU{color:red}.classS{color:red}.classT{color:red}}
.classNew{margin: 10px}
Обратите внимание, что на этом этапе все строки, кроме последней, заканчиваются на }}
, а }}
никогда не существует внутри строки. Правило 3 выше удовлетворяется этим шагом.
второй неправильный шаг
Второй шаг awk
получает вышеупомянутый вывод от первого шага через канал. Он выполняет две функции:
Во-первых, процедура проверяет, закрыт ли первый открывающий блок {
в строке }
перед открытием другого. Если он закрыт, новая строка вводится для оставшейся части строки, если только для конкретного случая, когда вторая }
происходит только после одного открытия {
, как в третьей строке вывода выше @media only screen and (min-width: 1441px){.classX(color:blue}}
(это может быть опечатка в исходном файле, где (
следующее .classX
должно было быть {
). Проверка станет неактуальной, но безвредной, если это была опечатка и ее исправят. (см. заключительное примечание для исправления).
Проверка производится путем разделения строки ввода на поля, разделенные знаком {
. Разделитель полей устанавливается в блоке BEGIN
. В то же время разделитель полей вывода устанавливается на ту же открывающую фигурную скобку, чтобы заменить {
при печати полей:
BEGIN{FS = "{"; OFS = "{"}
Теперь, если в поле 2 встречается }
, то он закрывает первый блок до того, как был открыт другой, и поэтому после закрытия с помощью замены вставляется разрыв строки:
$2~"}"{if (NF>2) sub("}","}\n",$2);}
Обратите внимание на использование условия pattern
$2~"}"
, которое применяет действие, только если }
появляется в поле 2. Это удовлетворяет правилу 1 выше.
Во-вторых, процедура проверяет каждое поле после первого, чтобы увидеть, содержит ли оно медиа-запрос, если присутствует @
, выполняется замена, чтобы вставить разрыв строки перед ним, чтобы медиа-запрос начинался с новой строки (правило 2).
Последний блок action
во второй awk
процедуре печатает измененную строку.
Вторая процедура полностью следует (обратите внимание, что это не будет работать без передачи в нее вывода первой процедуры или в виде файла:
awk 'BEGIN{FS = "{"; OFS = "{"} $2~"}"{if (NF>2) sub("}","}\n",$2);} {for(i=2;i<=NF;++i) sub("@","\n@",$i)} {print}'
вся процедура
Вот две процедуры, объединенные трубой:
awk 'BEGIN{FS = "}}"} {for(i=1;i<NF;i++) print $i"}}"; print $NF}' mini.css | awk 'BEGIN{FS = "{"; OFS = "{"} $2~"}"{if (NF>2) sub("}","}\n",$2);} {for(i=2;i<=NF;++i) sub("@","\n@",$i)} {print}'
Обратите внимание, что файл данных, названный в данном случае mini.css
, является аргументом первой процедуры awk
. Выходные данные первой процедуры передаются во вторую.
результаты теста
(Протестировано на терминале Mac с использованием GNU Awk 5.2.0)
Это вывод данных примера одной строки в вопросе, сохраненных как mini.css
и обработанных с использованием комбинированных скриптов awk
выше в рамках всей процедуры:
.class{margin:0px}
.class1,.class2{margin 0px}
@media{.class{color:blue}.class1,.class2{color:red}}
@media{.classA.classB,.classC{margin:0px}}
@media{.classD,.classE{color:blue}.class1,.class2{color:red}}
@media only screen and (min-width: 1441px){.classX(color:blue}}
@media only screen and (min-width: 1441px){.class{color:blue}.class1,.class2{color:red}}
@media only screen and (min-width: 1441px){.classA.classB,.classC{margin:0px}}
@media only screen and (inverted-colors){.classD,.classE{color:blue}.class1,.class2{color:red}.classV{color:red}.classR{color:red}.classU{color:red}.classS{color:red}.classT{color:red}}
.classNew{margin: 10px}
примечание относительно возможной опечатки Если эта часть исходных данных:
@media only screen and (min-width: 1441px){.classX(color:blue}}
должен был быть:
@media only screen and (min-width: 1441px){.classX{color:blue}}
тогда if (NF>2)
во второй процедуре становится лишним. Рабочие объединенные процедуры будут тогда:
awk 'BEGIN{FS = "}}"} {for(i=1;i<NF;i++) print $i"}}"; print $NF}' mini.css | awk 'BEGIN{FS = "{"; OFS = "{"} $2~"}"{sub("}","}\n",$2);} {for(i=2;i<=NF;++i) sub("@","\n@",$i)} {print}'
Если предложенный вами подход не работает так, как вам хотелось бы, не могли бы вы сказать, почему он не делает то, что вы хотите?