Sed: измените каждое непервое повторение слова для каждого слова в тексте

Попробуйте -m флаг, возможно, объединенный с -T и/или -x (или -x standalone).

3
25.11.2018, 02:24
2 ответа

Если ваш ввод не содержит <, > или + символов, вы можете сделать:

sed '
  s/[[:alnum:]]\{1,\}/<&>/g;:1
  s/\(<\([^>]*\)>.*\)<\2>/\1+\2+/;t1
  s/[<>]//g'

Если это возможно, вы всегда можете избежать их:

sed '
  s/:/::/g;s/</:{/g;s/>/:}/g
  s/[[:alnum:]]\{1,\}/<&>/g;:1
  s/\(<\([^>]*\)>.*\)<\2>/\1+\2+/;t1
  s/[<>]//g
  s/:}/>/g;s/:{/</g;s/::/:/g'

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

sed '
  :2
  $!{N;b2
  }
  s/:/::/g;s/</:{/g;s/>/:}/g
  s/[[:alnum:]]\{1,\}/<&>/g;:1
  s/\(<\([^>]*\)>.*\)<\2>/\1+\2+/;t1
  s/[<>]//g
  s/:}/>/g;s/:{/</g;s/::/:/g'

Это будет довольно неэффективно и было бы намного проще с perl:

perl -pe 's/\w+/$seen{$&}++ ? "+$&+" : $&/ge'

На основе строк:

perl -pe 'my %seen;s/\w+/$seen{$&}++ ? "+$&+" : $&/ge'
4
27.01.2020, 21:16

Вот еще один подход: это использует несколько SED :

an='[:alnum:]' esc=$(printf '\033\[')
sed "/[${an}]/!d;=;a\ }
    s/.*/ & /;s/[^${an}]\{1,\}/   /g
    s| \([${an}"']\{1,\}\) | \
    s/\\([^+'"${an}"']\\)\\(\1\\)\\([^+'"${an}"']\\)/\\1+\\2+\\3/2|g
' <text |
sed '/^ /!N;s/\n */{/' |
sed -e 's/.*/ & /;s/+/ & /g' \
    -f - \
    -e "s/ //;s/ $//
        s/+[^+ ]\{1,\}+/${esc}38;5;35m&${esc}0m/g
        s/ + /+/g" text

в основном, первые два SED , чтобы написать скрипт на третий. Первый SED очищает все, кроме буквенно-цифровых символов с каждой строки - и пропускает полностью любую строку без одного. Для всех групп персонажей, которые остаются, он пишет заявление подстановки, что третьи в конечном итоге (почти мгновенно) прочитано и интерпретировать как его скрипт.

Второе SED необходимо, потому что первое пишет свой скрипт по линии - и каждая строка может иметь несколько /// утверждений. Первые печатает свой номер строки для каждой строки, который содержит буквенно-цифровую, но это необходимо подключить в контексте функции для третьего SED - и поэтому второй делает это.

Вот образец того, как выглядит сценарий:

...
43{
    s/\([^+[:alnum:]]\)\(n\)\([^+[:alnum:]]\)/\1+\2+\3/2  
    s/\([^+[:alnum:]]\)\(N\)\([^+[:alnum:]]\)/\1+\2+\3/2  
    s/\([^+[:alnum:]]\)\(G\)\([^+[:alnum:]]\)/\1+\2+\3/2  
 }
44{
    s/\([^+[:alnum:]]\)\(b\)\([^+[:alnum:]]\)/\1+\2+\3/2  
    s/\([^+[:alnum:]]\)\(block\)\([^+[:alnum:]]\)/\1+\2+\3/2  
 }
45{
    s/\([^+[:alnum:]]\)\(END\)\([^+[:alnum:]]\)/\1+\2+\3/2  
    s/\([^+[:alnum:]]\)\(SEDSCRIPT\)\([^+[:alnum:]]\)/\1+\2+\3/2  
 }

Существует трейлинг 2 для каждого /// - это потому, что каждая замена направлена ​​на Второе возникновение каждого рисунка - если второе происшествие не существует, ничего не замещена. Вышеуказанное является результатом пробега его на другом из моих SED скриптов - кажется довольно невосприимчивым к специальным персонажам или подобным.

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

s/+[^+ ]\{1,\}+/${esc}38;5;35m&${esc}0m/g

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

Вот сценарий, который он пишет для вашего примера данных:

1{
    s/\([^+[:alnum:]]\)\(qq\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(xyz\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(qq\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(aa\)\([^+[:alnum:]]\)/\1+\2+\3/2 
    s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/\1+\2+\3/2
 }

Вот что он печатает:

qq    ab xyz     +ab+ +qq+ aa +ab+

и из некоторых из моих SED скрипт от ранее:

        s/\(\(.\)${bs}\2\)\{1,\}/${esc}38;5;35m&${+esc+}0m/g
        s/\(_${bs}[^_]\)\{1,\}/${esc}38;5;75m&${+esc+}0m/g
        s/.${bs}//g
        s/\(\(${esc}\)0m\2[^m]*+m+[_ ]\{,+2+\}\)\{+2+\}/_/g
n;      /./!N;G
1
27.01.2020, 21:16

Теги

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