Есть ли способ сделать несколько замен с помощью sed, не связывая замены?

Браузеры в основном используют/dev/random(случайное ), так как/dev/urandom(псевдослучайное )не считается надежным (, но, как указывает страница руководства случайный (4 ), это не должно так и быть ).

Как оказалось, мой ноутбук не имеет ни TPM , ни DRNG для эффективной генерации случайных чисел, в результате чего любой, кому нужны случайные числа сразу после загрузки, будет ждать, пока не будет достаточно энтропии. собрались. Таким образом, он должен генерировать случайные числа из таких вещей, как клавиатура, мышь, вентилятор и т. д. Это означает, что вы можете ускорить этот процесс генерации энтропийных (случайных чисел ), перемещая мышь или печатая на клавиатуре. Доступную энтропию можно проверить с помощью cat /proc/sys/kernel/random/entropy_avail.

Если бы Chrome просто использовал urandomвместо random, такой проблемы не было бы. Но это легко исправить, питая randomотurandom:

1 )Установить кольца -инструменты

2 )Запустите sudo rngd -o /dev/random -r /dev/urandomперед запуском браузера, скажем, в~/.xinitrc

18
02.02.2021, 14:07
8 ответов

Это та проблема, когда вам нужен цикл, чтобы вы могли искать оба шаблона одновременно.

awk '
    BEGIN {
        regex = "A|B"
        map["A"] = "BB"
        map["B"] = "AA"
    }
    {
        str = $0
        result = ""
        while (match(str, regex)) {
            found = substr(str, RSTART, RLENGTH)
            result = result substr(str, 1, RSTART-1) map[found]
            str = substr(str, RSTART+RLENGTH)
        }
        print result str
    }
'

Конечно, если доступен Perl, то есть эквивалентный однострочник:

perl -pe '
    BEGIN { %map = ("A" => "BB", "B" => "AA"); }
    s/(A|B)/$map{$1}/g;
'

Если ни один из шаблонов не содержит специальных символов, вы также можете создать регулярное выражение динамически:

perl -pe '
    BEGIN {
        %map = ("A" => "BB", "B" => "AA");
        $regex = join "|", keys %map;
    }
    s/($regex)/$map{$1}/g;
'

Между прочим, в Tcl есть встроенная команда для этого, называемая string map, но писать однострочники Tcl непросто.


Демонстрация эффекта сортировки ключей по длине:

  1. без сортировки

    $ echo ABBA | perl -pe '
        BEGIN {
            %map = (A => "X", BB => "Y", AB => "Z");
            $regex = join "|", map {quotemeta} keys %map;
            print $regex, "\n";
        }
        s/($regex)/$map{$1}/g
    '
    
    A|AB|BB
    XYX
    
  2. с сортировкой

    $ echo ABBA | perl -pe '
          BEGIN {
              %map = (A => "X", BB => "Y", AB => "Z");
              $regex = join "|", map {quotemeta $_->[1]}
                                 reverse sort {$a->[0] <=> $b->[0]}
                                 map {[length, $_]}
                                 keys %map;
              print $regex, "\n";
          }
          s/($regex)/$map{$1}/g
      '
    
    BB|AB|A
    ZBX
    

Сравнительный анализ «простой» сортировки и сортировки Шварца в Perl :Код подпрограмм взят непосредственно изsortдокументации

#!perl
use Benchmark   qw/ timethese cmpthese /;

# make up some key=value data
my $key='a';
for $x (1..10000) {
    push @unsorted,   $key++. "=". int(rand(32767));
}

# plain sorting: first by value then by key
sub nonSchwartzian {
    my @sorted = 
        sort { ($b =~ /=(\d+)/)[0] <=> ($a =~ /=(\d+)/)[0] || uc($a) cmp uc($b) } 
        @unsorted
}

# using the Schwartzian transform
sub schwartzian {
    my @sorted =
        map  { $_->[0] }
        sort { $b->[1] <=> $a->[1] || $a->[2] cmp $b->[2] }
        map  { [$_, /=(\d+)/, uc($_)] } 
        @unsorted
}

# ensure the subs sort the same way
die "different" unless join(",", nonSchwartzian()) eq join(",", schwartzian());

# benchmark
cmpthese(
    timethese(-10, {
        nonSchwartzian => 'nonSchwartzian()',
        schwartzian    => 'schwartzian()',
    })
);

запуск:

$ perl benchmark.pl
Benchmark: running nonSchwartzian, schwartzian for at least 10 CPU seconds...
nonSchwartzian: 11 wallclock secs (10.43 usr +  0.05 sys = 10.48 CPU) @  9.73/s (n=102)
schwartzian: 11 wallclock secs (10.13 usr +  0.03 sys = 10.16 CPU) @ 49.11/s (n=499)
                 Rate nonSchwartzian    schwartzian
nonSchwartzian 9.73/s             --           -80%
schwartzian    49.1/s           405%             --

Код, использующий преобразование Шварца, работает в 4 раза быстрее.

Где функция сравнения толькоlengthкаждого элемента:

Benchmark: running nonSchwartzian, schwartzian for at least 10 CPU seconds...
nonSchwartzian: 11 wallclock secs (10.06 usr +  0.03 sys = 10.09 CPU) @ 542.52/s (n=5474)
schwartzian: 10 wallclock secs (10.21 usr +  0.02 sys = 10.23 CPU) @ 191.50/s (n=1959)
                Rate    schwartzian nonSchwartzian
schwartzian    191/s             --           -65%
nonSchwartzian 543/s           183%             --

Шварцеван намного медленнее с этой недорогой функцией сортировки.

Теперь можно обойтись без оскорбительного комментария?

13
18.03.2021, 22:33

Вы можете сделать это с помощью GNU sed, изменив все Asна разделитель записей \n, которого наверняка не будет.

echo AYB |
sed -e '
  y/A/\n/
  s/[\nB]/&&/g
  y/\nB/BA/
'
BBYAA
6
18.03.2021, 22:33

Я полагаю, что одно из решений состоит в том, чтобы заменить сначала A или B другим символом, отсутствующим в строке, а затем заменить этот символ. Таким образом можно избежать переключения между A и B. Хотя нужна цепочка из sed:

$ echo AYB | sed -e 's/A/#/g' -e 's/B/AA/g' -e 's/#/BB/g'
BBYAA
6
18.03.2021, 22:33

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

Предположим, что две подстроки Aи Bявляются одиночными символами...

Вы хотите преобразовать AYBв BBYAA. Для этого

  1. Измените Aна Bи Bна Aс помощью y/AB/BA/.
  2. Замените каждый Aв новой строке на AA, используя s/A/AA/g.
  3. Замените каждый Bв новой строке на BB, используя s/B/BB/g.
$ echo AYB | sed 'y/AB/BA/; s/B/BB/g; s/A/AA/g'
BBYAA

Объедините два последних шага, чтобы получить

$ echo AYB | sed 'y/AB/BA/; s/[AB]/&&/g'
BBYAA

На самом деле порядок операций здесь не имеет большого значения:

$ echo AYB | sed 's/[AB]/&&/g; y/AB/BA/'
BBYAA

Команда редактирования sedy///преобразует символы в своем первом аргументе в соответствующие символы во втором аргументе, как это делает утилита tr. Это делается за одну операцию, поэтому вам не нужно использовать временный файл для замены Aи Bв y/AB/BA/. В общем, y///намного быстрее при переводе отдельных символов, чем то, что, например. s///gравно (, так как регулярные выражения не используются ), и он также может вставлять символы новой строки в строки с помощью \n, чего стандартная команда s///не может делать(s///в GNU sedочевидно, может сделать это как не -портативное удобное расширение ).

Символ &в замещающей части команды s///будет заменен любым выражением в первом аргументе, таким образом, s/[AB]/&&/gудвоит любой символ Aили Bво входных данных. данные.


Для многосимвольных подстрок -, предполагая, что подстроки различны (, т. е. одна подстрока не находится в другой, как в случае ooи foo), используйте что-то вроде

$ echo fooxbar | sed 's/foo/@/g; s/bar/foofoo/g; s/@/barbar/g'
barbarxfoofoo

То есть,поменять местами две строки через промежуточную строку, иначе не найденную в данных. Обратите внимание, что промежуточной строкой может быть любая строка, не найденная в данных, а не только один символ.

14
18.03.2021, 22:33

С помощью awkвы можете использовать шаблон1 в качестве разделителя полей FSи замену1 в качестве разделителя выходных полей OFS. Затем переберите каждое поле и замените pattern2 на replace2:

awk '{for (f=1;f<=NF;f++){gsub(p,r,$f)} $1=$1}1' FS=A OFS=BB p=B r=AA file

Суть$1=$1заключается в принудительном восстановлении записи , в противном случае, например, для 0Aпроизойдет сбой.

Это соответствует стандарту POSIX и не требует промежуточной строки, что делает его надежным.

9
18.03.2021, 22:33

It's OK if it uses something other than sed or tr.

Dyalog APL⎕R("quad -R" )Оператор замены PCRE(полная документация)выполняет параллельное сопоставление:

patterns ← ⎕JSON'["A","B"]'
substitutions ← ⎕JSON'["BB","AA"]'
Transform ← patterns ⎕R substitutions
⎕← Transform ⍞

Попробуйте онлайн!

В приведенном выше я все расписал для ясности, но для создания функции, которая это делает, вам нужно только:

(,¨'AB')⎕R'BB' 'AA'

Попробуйте на TryAPL!

Полное раскрытие информации :Я работаю в компании Dyalog Ltd., поставщике Dyalog APL.

4
18.03.2021, 22:33

Этого можно добиться для произвольного вводимого текста с последовательностью прямых замен, используяsed:

sed 's/Q/Qz/g; s/A/Qa/g; s/B/AA/g; s/Qa/BB/g; s/Qz/Q/g;'

Открытие пространства токена -для хранения или представления промежуточных/произвольных значений

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

Хитрость заключается в том, что вы сначала создаете токен -пробел (, то есть переменное пространство )внутри промежуточной копии текста, которое можно использовать для представления произвольных значений, таких, что токены, которые вы используете в последующих заменах не может существовать в промежуточной копии текста, поскольку вы делаете дальнейшие замены. Например:

s/Q/Qz/g

Это приводит к тому, что текст больше не может содержать никакого Q, за которым следует ничего , кроме z, и каждый Qzфактически представляет собой Q. Это означает, что вы можете использовать Q, за которым следует любой символ, кроме z, для обозначения всего, что вы пожелаете.

В этом конкретном случае вы также не можете использовать QAи QB, потому что вы хотите сделать замену отдельных символов Aи B.

Таким образом, чтобы произвести полную замену, которую вы желаете, вы должны выполнить следующую последовательность замен:

s/Q/Qz/g  # Open your Q* token-space.
          # You can now use any Q* other than Qz, QA, and QB to represent another value.
          # The restriction to not use QA and QB is only because this specific case requires
          # substituting for the single A and B characters.
s/A/Qa/g  # Temporarily represent all A as Qa.
s/B/AA/g  # Change all B to AA, as desired in the question.
s/Qa/BB/g # Change all Qa placeholders with BB.
s/Qz/Q/g  # Restore all Q, closing the token-space.

Таким образом, в целом это можно записать как:

sed 's/Q/Qz/g; s/A/Qa/g; s/B/AA/g; s/Qa/BB/g; s/Qz/Q/g;'

Получается вывод:

 $ echo AYB | sed 's/Q/Qz/g; s/A/Qa/g; s/B/AA/g; s/Qa/BB/g; s/Qz/Q/g;'
 BBYAA

Что происходит:

Замена Текст в буфере Комментарий
s/Q/Qz/gAYBОткройте место для Q*токена -. Это ничего не делает с этим примером ввода, но гарантирует, что это будет работать с произвольным вводом текста.
s/A/Qa/gQaYBВременно представить все Aкак Qa.
s/B/AA/gQaYAAИзмените все Bна AA, как указано в вопросе.
s/Qa/BB/gBBYAAЗамените все заполнители Qaна BB.
s/Qz/Q/gBBYAAВосстановить все Q, закрыв пространство маркера -. Опять же, ничего не делает с этим примером ввода текста, но необходимо для работы с произвольным вводом текста.

Вы можете использовать любой символ в качестве первого символа в вашем токене -пробел

В качестве первого символа пробела вашего токена -вы можете использовать любой отдельный символ. Обычно я использую Q, потому что оно редко встречается в тексте, является буквой в наборе символов ASCII и легко запоминается. Zтоже подойдет. Если вы используете более широкий набор символов, лучше выбрать символ, возможно, символ, который используется еще реже. Из соображений производительности идеальным было бы выбрать символ, которого нет в тексте, который вы будете использовать, чтобы первая и последняя замены фактически ничего не делали. Однако это касается только производительности и пространства, а не функциональности. Другими словами, он будет работать с любым персонажем, которого вы выберете, но будет быстрее, если ему придется выполнять меньше работы.

Проблемы

  1. Любые шаблоны, которые могут конкретно зависеть от символа, который вы используете в качестве начала пространства вашего токена -, должны учитывать, что он представлен выбранным вами токеном. В приведенном выше случае, если вы хотите сделать некоторые другие замены с символами Q, вам нужно либо учесть все Q, представленные в промежуточном тексте как Qz, либо выполнить эти замены перед открытием вашего маркера -пробел или после его закрытия. В основном,вы можете решить эту проблему, просто выбрав другого персонажа в качестве начального символа для вашего маркера -.
  2. Это не самый экономичный способ с точки зрения использования ЦП и пространства. Реальные языки программирования могут выполнять задачи такого типа значительно эффективнее, используя различные другие конструкции. Это, однако, хорошая техника, которую нужно иметь в заднем кармане, когда замена является инструментом, который у вас есть.
6
18.03.2021, 22:33
#stuff match=>replacement pairs and export them
export vA="X"
export vBB="Y"
export vAB="Z"


#GNU sed used here

# dynamically build the regex
re=
for i in A BB AB; do
  re=${re-}${re:+\|}${i}
done
echo "regex = $re" 

#give it a spin... 
echo ABBA |
sed -E \
  -e 'p' \
  -e "s/($re)/\n&\n/g;:a" \
  -e "s/^([^\n]*)\n($re)\n(.*)/echo \"\1\${v\2}\3\"/e;ta" \
;
regex = A|BB|AB
ABBA
ZBX

Как мы заметили, sed использует самое длинное совпадение при сопоставлении в заданной позиции во входной строке, в отличие от perl, который выбирает самое левое совпадение. Таким образом, бремя сортировки по длине не лежит на пользователе.

0
18.03.2021, 22:33

Теги

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