Как заменить сразу несколько шаблонов на sed?



Предположим, у меня есть строка 'abbc' и я хочу заменить:




  • ab - > bc

  • bc - > ab


Если я попробую два заменяет результат не то, что я хочу:



echo 'abbc' | sed 's/ab/bc/g;s/bc/ab/g'
abab


Итак, какую команду sed я могу использовать для замены, как показано ниже?



echo abbc | sed SED_COMMAND
bcab


EDIT:
На самом деле текст может иметь более 2 шаблонов, и я не знаю, сколько замен мне понадобится. Поскольку был ответ, говорящий, что sed - это редактор потока и его замены жадно я думаю, что мне нужно будет использовать какой-то язык сценариев для этого.

736   7  

7 ответов:

может, что-то вроде этого:

sed 's/ab/~~/g; s/bc/ab/g; s/~~/bc/g'

заменить ~ символ, который вы знаете, не будет в строке.

вот вариация на тему ответ УГА это работает для нескольких пар поиска и замены без необходимости проверять, как значения могут быть повторно использованы:

sed -i '
s/\bAB\b/________BC________/g
s/\bBC\b/________CD________/g
s/________//g
' path_to_your_files/*.txt

вот пример:

перед:

some text AB some more text "BC" and more text.

после:

some text BC some more text "CD" and more text.

отметим, что \b обозначает границы слов, что и мешает ________ от вмешательства в поиск (я использую GNU sed 4.2.2 на Ubuntu). Если вы не используете границу слова ищите, тогда эта техника может не сработать.

также обратите внимание, что это дает те же результаты, что и удаление s/________//g и добавить && sed -i 's/________//g' path_to_your_files/*.txt до конца команды, но не требует указания пути дважды.

общее изменение на этом можно было бы использовать \x0 или _\x0_ на месте ________ если вы знаете, что никакие нули не появляются в ваших файлах,как предложил Джилл.

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

echo 'abcd' | sed -e 's/ab/xy/;s/cd/ab/;s/xy/cd/'

Это может сработать для вас (GNU sed):

sed -r '1{x;s/^/:abbc:bcab/;x};G;s/^/\n/;:a;/\n\n/{P;d};s/\n(ab|bc)(.*\n.*:()([^:]*))/\n/;ta;s/\n(.)/\n/;ta' file

Это использует таблицу поиска, которая подготовлена и хранится в пространстве хранения (HS), а затем добавляется к каждой строке. Уникальный маркер (в данном случае \n) добавляется к началу строки и используется в качестве метода для bump-вдоль поиска по всей длине строки. Как только маркер достигает конца строки, процесс завершается и распечатывается таблица поиска и маркеры отбрасываются.

N. B. The таблица поиска подготавливается в самом начале и второй уникальный маркер (в данном случае :) выбрано так, чтобы не конфликтовать со строками подстановки.

С некоторыми комментариями:

sed -r '
  # initialize hold with :abbc:bcab
  1 {
    x
    s/^/:abbc:bcab/
    x
  }

  G        # append hold to patt (after a \n)

  s/^/\n/  # prepend a \n

  :a

  /\n\n/ {
    P      # print patt up to first \n
    d      # delete patt & start next cycle
  }

  s/\n(ab|bc)(.*\n.*:()([^:]*))/\n/
  ta       # goto a if sub occurred

  s/\n(.)/\n/  # move one char past the first \n
  ta       # goto a if sub occurred
'

таблица работает следующим образом:

   **   **   replacement
:abbc:bcab
 **   **     pattern

Я всегда использую несколько операторов с "- e"

$ sed -e 's:AND:\n&:g' -e 's:GROUP BY:\n&:g' -e 's:UNION:\n&:g' -e 's:FROM:\n&:g' file > readable.sql

это добавит '\n 'перед всеми AND, GROUP BY, UNION и FROM, тогда как' & 'означает согласованную строку и' \n& ' означает, что вы хотите заменить согласованную строку на '\n' перед 'согласованной'

Tcl имеет builtin для этого

$ tclsh
% string map {ab bc bc ab} abbc
bcab

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

в perl:

perl -E '
    sub string_map {
        my ($str, %map) = @_;
        my $i = 0;
        while ($i < length $str) {
          KEYS:
            for my $key (keys %map) {
                if (substr($str, $i, length $key) eq $key) {
                    substr($str, $i, length $key) = $map{$key};
                    $i += length($map{$key}) - 1;
                    last KEYS;
                }
            }
            $i++;
        }
        return $str;
    }
    say string_map("abbc", "ab"=>"bc", "bc"=>"ab");
'
bcab

здесь awk на основе oogas sed

echo 'abbc' | awk '{gsub(/ab/,"xy");gsub(/bc/,"ab");gsub(/xy/,"bc")}1'
bcab

Comments

    Ничего не найдено.