замените несколько запятых сторона один или несколько наборов фигурных скобок и исключения это в одном или нескольких наборах фигурных скобок

find source-dir -print0 | xargs -0 -I % pv % > dest-dir/%
2
09.10.2014, 15:33
4 ответа

Я придумал несколько способов сделать это в SED , но самое сломалось в угловых случаях. Один, однако, не:

sed 's/^/\n/;:b
/\n\n/!s/\(\n[^,{}]*\),/\1|/;tb
s/\(\n\n*\)\([^{}]*[{}]\)/\2\1/
s/{\(\n\)/&\1/;s/\(}\n\)\n/\1/;tb
s/\n//g' <<\DATA
(999969,2500,"777777888",0,"45265","65522",NULL,10001,2014-09-15 10:27:07.287,2014-09-15 10:28:49.085,2014-09-15 06:28:50.000,0,0,NULL,"text","401c4133091977",{F,F,"711592473,"00967711580001,F,NULL,NULL,"421010617759466","'401c4133091977H'",NULL,NULL,NULL,NULL,NULL,NULL,1,1,10,1,0,0,0,"a30200000000276f",NULL},NULL,{gggg{-1, 0, -1, 1410762530000, 87, 0, 0}, rrrr[{"foot", 24000, 976000, 3999-12-31 23:59:59, 0}], rrrr[{1000003, 1410762443000, 120, 87, 0, 0, 2, 1, 24000, 0, 0}]},{dd=0, ff=0, gg=0, hh=1, ctr="live", dddd="52265", eni=55, cuc=1},NULL,NULL,NULL,NULL,NULL,{NULL,NULL,NULL,0,"wwww","eeee",2014-10-10 10:45:59.000,2015-03-09 23:59:59.000,2015-06-07 23:59:59.000,2015-08-06 23:59:59.000,NULL},poopoer,sciioooper)
DATA

, что шаги по линии данных с использованием разделителя, вы можете быть уверены, чтобы не найти на линии - новой символ. Он проводит линию слева направо, остановка в ближайшем из двух интересных точек - символов } {. Когда он останавливается на {, он добавляет новенький символ к его разделителю; Когда на } } он вычитает один, если они должны иметь два.

Когда он остановлен в точке, в котором можно найти только один новенький символ, который можно найти на линии, и запятую следует за своим разделителем перед либо {} , он заменит его трубой и рекурсировать Вернуться, чтобы попробовать те же тест на замену снова.

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

Выход из вашего образца:

(999969|2500|"777777888"|0|"45265"|"65522"|NULL|10001|2014-09-15 10:27:07.287|2014-09-15 10:28:49.085|2014-09-15 06:28:50.000|0|0|NULL|"text"|"401c4133091977"|{F,F,"711592473,"00967711580001,F,NULL,NULL,"421010617759466","'401c4133091977H'",NULL,NULL,NULL,NULL,NULL,NULL,1,1,10,1,0,0,0,"a30200000000276f",NULL}|NULL|{gggg{-1, 0, -1, 1410762530000, 87, 0, 0}, rrrr[{"foot", 24000, 976000, 3999-12-31 23:59:59, 0}], rrrr[{1000003, 1410762443000, 120, 87, 0, 0, 2, 1, 24000, 0, 0}]}|{dd=0, ff=0, gg=0, hh=1, ctr="live", dddd="52265", eni=55, cuc=1}|NULL|NULL|NULL|NULL|NULL|{NULL,NULL,NULL,0,"wwww","eeee",2014-10-10 10:45:59.000,2015-03-09 23:59:59.000,2015-06-07 23:59:59.000,2015-08-06 23:59:59.000,NULL}|poopoer|sciioooper)
0
27.01.2020, 22:00

Не оказаться в Afaid это сложно SED заявление . Но это должно уважать каскадирование. Вот в одной строке:

sed -e 's/,/|/g;:a;s/{\([^{}]*\)|\([^{}]*\)}/{\1,\2}/g;ta;s/{\([^{}]*\)}/<\1>/g;ta;:b;s/<\([^<>]*\)>/{\1}/g;tb' file

вот комментарированная версия:

sed -e '
        s/,/|/g;                                 #replaces all commas (,) with pipes (|)
        :a;                                      #sets a label called a
            s/{\([^{}]*\)|\([^{}]*\)}/{\1,\2}/g; #replaces {a|b|c} with {a,b|c}
          ta;                                    #go back to the label `a` and repeat the
                                                 #prevous part until there is nothing more
                                                 #to replace: when {a|b|c} became {a,b,c}
          s/{\([^{}]*\)}/<\1>/g;                 #replace {...} with <...>
        ta;                                      #go back to label a again until all {} are 
                                                 #replaces by <>
        :b;                                      #create a new label called b
          s/<\([^<>]*\)>/{\1}/g;                 #replace <...> back to {...}
        tb;                                      #and back to label b to repeat the previous
                                                 #part
' file

с этим я получил желаемый выход.

0
27.01.2020, 22:00

Это можно сделать просто через Perl+regex комбинацию.

perl -pe 's/(\{(?:[^{}]|(?1))*\})(*SKIP)(*F)|,/|/g' file

Пример:

$ perl -pe 's/(\{(?:[^{}]|(?1))*\})(*SKIP)(*F)|,/|/g' file
(999969|2500|"777777888"|0|"45265"|"65522"|NULL|10001|2014-09-15 10:27:07.287|2014-09-15 10:28:49.085|2014-09-15 06:28:50.000|0|0|NULL|"text"|"401c4133091977"|{F,F,"711592473,"00967711580001,F,NULL,NULL,"421010617759466","'401c4133091977H'",NULL,NULL,NULL,NULL,NULL,NULL,1,1,10,1,0,0,0,"a30200000000276f",NULL}|NULL|{gggg{-1, 0, -1, 1410762530000, 87, 0, 0}, rrrr[{"foot", 24000, 976000, 3999-12-31 23:59:59, 0}], rrrr[{1000003, 1410762443000, 120, 87, 0, 0, 2, 1, 24000, 0, 0}]}|{dd=0, ff=0, gg=0, hh=1, ctr="live", dddd="52265", eni=55, cuc=1}|NULL|NULL|NULL|NULL|NULL|{NULL,NULL,NULL,0,"wwww","eeee",2014-10-10 10:45:59.000,2015-03-09 23:59:59.000,2015-06-07 23:59:59.000,2015-08-06 23:59:59.000,NULL})

Пояснение:

Я разделил регекс на две части для объяснения.

  1. (\{(?:[^{}]|(?1))*\})
  2. (*SKIP)(*F)|,

1-я часть

(\{(?:[^{}]|(?1))*\})
  • Этот трюк сработает только в том случае, если фигурные скобки будут правильно спарены.
  • () Это захватывающие группы, используемые для захвата символов.
  • \{ совпадает с открывающейся фигурной скобкой.
  • (?:[^{}]|(?1))

    • (?:...) Называется захватывающая группа.
    • [^{}] Он будет совпадать с любым символом, но не с { или }
    • | Логическим оператором ИЛИ.
    • (?1) Получает первую группу захвата.
  • (?:[^{}]|(?1))* Сопоставляет предыдущий токен нулю или более раз.
  • \} Закрытие символа }.

Рассмотрим пример ниже и схему, которая соответствует вложенным скобкам в этом примере.

Строка:

h{foo{bar}foobar}

Образец:

h(\{(?:[^{}]|(?1))*\})
  • Сначала регрессионный движок пытается сопоставить h (, который был в образце) со вложенной строкой. Таким образом, первая буква h совпадает.
  • Шаблон для нахождения сбалансированной скобки подается в группу захвата.
  • Теперь движок берет второй символ (т.е. \{) в шаблоне и пытается найти совпадение с входной строкой. Итак, первый { получил захват. Я использовал слово захваченное вместо совпадения, потому что \{ находится внутри захватывающей группы.
  • (?:[^{}]|(?1))* Это говорит регрессионному движку, что любой символ, кроме { или }, должен совпадать с любым символом, кроме { или } нуля или более раз. Если вы нашли любой символ { или }, то вернитесь к первой захваченной группе еще раз. Итак, теперь строка foo была перехвачена. Следующим символом является {, поэтому он возвращается к первой захваченной группе. Теперь регрессионный движок на один уровень ниже в рекурсии. Какой первый паттерн в нашей первой группе захвата ( см. регекс)? Это \{, теперь он совпадает с символом {, который был сразу за строкой foo.
  • Движок все еще находится на одном уровне глубоко в рекурсии, опять же шаблон (?:[^{}]|(?1))* совпадает со строкой bar. Теперь символ после bar равен }, поэтому после совпадения со строкой bar регрессионный движок не попадет в (?1), поэтому мы заставили группу без захвата повторить нуль или более раз. Следующий шаблон (шаблон после к (?:[^{}]|(?1))*) в регексе это \}. Таким образом, эта \} будет соответствовать } скобке, которая была сразу после бар. Теперь регенератор выходит из одного уровня глубоко в рекурсии, и шаблон [^{}]* будет соответствовать следующей строке foobar . Последняя \} будет соответствовать последней фигурной скобке.
  • Теперь наша 1-я группа захвата содержит {foo{bar}foobar}.

2-я часть

  • (*SKIP)(*F) приводит к тому, что символы, которые совпадают или перехватываются, не срабатывают. Так что в нашем случае все захваченные сбалансированные фигурные скобки были пропущены. То есть, это заставляет регрессионный движок соответствовать символам из оставшейся строки.
  • Синтаксис или формат (*SKIP)(*F)

     part1(*SKIP)(*F)|part2.
     | |
     |---- -----> Сопоставьте это.
    Не совпадай с этим 
    
  • Таким образом, шаблон, который был сразу после |, будет пытаться сопоставить символы из оставшейся строки (строки, за исключением вложенных скобок).

  • В нашем случае шаблон после | - это , . Таким образом, все запятые, находящиеся вне вложенных скобок, совпали.

Прочтите это , чтобы понять Рекурсивное выражение . Примечание:

Примечание:

  • (?R) возвращает всю подмодель, т.е. полное совпадение. Мы также можем написать (?R) так как (?0)
  • (?1) восстанавливает первую подмакетку (т.е. паттерн внутри первой группы захвата)
4
27.01.2020, 22:00

Замените

,{ 

с

|{ 

и

}, 

с

}, 

с

}|

 echo "THING1,{THING2,{THING3,}},THING4" | sed -re "s/,\{/|{/gi" | sed -re "s/},/}|/gi"

результатами

THING1|{THING2|{THING3,}}|THING4
0
27.01.2020, 22:00

Теги

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