Советы по игре в гольф в седе


19

Какие общие советы у вас есть для игры в гольф в седе? Я ищу идеи, которые могут быть применены к задачам кода-гольфа и которые, по крайней мере, несколько специфичны для sed (например, «удалить комментарии» - это не ответ).

Пожалуйста, оставьте один совет за ответ.


4
На самом деле это не совет по игре в гольф (но все же совет по игре в гольф): перевод строки занимает столько же байтов, сколько точек с запятой, так что вы можете сделать свой код коротким и читаемым.
Деннис

Не совет, но проблема: у меня есть GNU sed, но Fкоманда никогда не работала. Кто-нибудь знает почему?
Сешумара

@seshoumara Fработает над моим GNU sed (тестирование Debian). Конечно, он печатает только -при чтении со стандартного ввода, но это ожидаемо. Что вы получаете от sed -e 'F;Q' /etc/hostname?
Тоби Спейт

@TobySpeight Это дает эту ошибку: char 1: unknown command: F. Возможно, мне нужно обновить sed; какая у вас версия? Команда Lтакже не работает, но в любом случае она бесполезна, поскольку -l nсуществует. Все остальное упомянутое на сайте GNU sed работает.
Сешумара

1
Я открыл чат bash, sed and dcдля всех, кто хочет поговорить и спросить об этих языках. Давайте сделаем сообщество!
сешумара

Ответы:


11

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

:    # define label ""
p    # print pattern space
b    # infinite loop! - branch to label ""


В самом деле, здесь также есть фактическая ссылка git commit . Я думаю, что для PPCG это не сильно изменится, так как нам разрешено публиковать ответы для GNU sed 4.2.x, но приятно знать, хотя и, к сожалению, официально этот трюк больше не будет работать.
Сешумара

8

Документация по GNU sed описывает sкоманду как «Швейцарский армейский нож sed» . Но если все, что вы хотите сделать, это заменить все экземпляры одного символа другим, yто вам нужна команда:

y/a/b/

один символ короче чем:

s/a/b/g

это также намного быстрее, и может поменять местами символы:y/12/21/
mikeserv

6

Попробуйте использовать расширенный синтаксис регулярных выражений (в GNU sed). -rВариант стоит один байт в выигрыше, но использовать его только один раз , чтобы исключить обратный слэш из пары \(...\)уже заплатил за себя.


2
С дополнительным примечанием, которое -rкажется sedспецифичным для GNU .
Манатворк

@manat - добавлено (но это ответ сообщества Wiki, так что вы могли бы отредактировать себя).
Тоби Спейт

Конечно. Я просто не считал это частью чаевых, только дополнительной запиской.
Манатворк

И он продолжает платить за себя при использовании +, ?, {}и |в регулярном выражении соответствует, так как нет обратных слэша не требуется ни.
Сешумара

-Eработает как псевдоним -rво многих sedреализациях, если я правильно помню.
PHK

6

При многократной замене в цикле:

loop:
s/foo/bar/g
tloop

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

# GNU sed
:
s/foo/bar/
t

Обратите также внимание на расширение GNU, приведенное выше: метка может иметь пустое имя, сохраняя больше ценных байтов. В других реализациях метка не может быть пустой, и переход без метки передает поток в конец скрипта (т.е. так же, как n).


1
Пустое имя метки зависит от GNU, POSIX требует, чтобы ветви без аргументов переходили в конец скрипта (похоже, это поведение в BSD и Busybox, также в GNU sed, если вы не добавляете пустую :)
ninjalj

2
Безымянный ярлык всегда был ошибкой в ​​GNU sed, а не расширением, и в версии 4.3 и выше эта ошибка, к сожалению, была исправлена. Смотрите здесь .
Сешумара

5

Там нет встроенной арифметики, но вычисления могут быть сделаны в одинарном или в десятичном формате. Следующий код преобразует десятичное число в UCD с x в качестве единицы и 0 в качестве разделителя цифр:

s/[1-9]/0&/g
s/[5-9]/4&/g
y/8/4/
s/9/4&/g
s/4/22/g
s/[37]/2x/g
s/[26]/xx/g
s/[1-9]/x/g

и вот преобразование обратно в десятичное:

s/0x/-x/g
s/xx/2/g
y/x/1/
s/22/4/g
s/44/8/g
s/81/9/g
s/42/6/g
s/21/3/g
s/61/7/g
s/41/5/g
s/-//g

Оба они взяты из ответа на «Умножение двух чисел без использования каких-либо чисел» .

Обычный старый унар может быть преобразован с помощью этой пары циклов из этого ответа в "{Curly Numbers};" где блок находится ;. Я использовал vи xчтобы соответствовать Роман для 5и 10; bпроисходит от "бис".

# unary to decimal
:d
/;/{
s/;;;;;/v/g
s/vv/x/g
/[;v]/!s/x\+/&0/
s/;;/b/g
s/bb/4/
s/b;/3/
s/v;/6/
s/vb/7/
s/v3/8/
s/v4/9/
y/;bvx/125;/
td
}

# Decimal to unary
:u
s/\b9/;8/
s/\b8/;7/
s/\b7/;6/
s/\b6/;5/
s/\b5/;4/
s/\b4/;3/
s/\b3/;2/
s/\b2/;1/
s/\b1/;0/
s/\b0//
/[^;]/s/;/&&&&&&&&&&/g
tu

1
... и если вам придется использовать любой из них, вы почти наверняка уже потеряли гольф-код, хотя вы все равно можете быть конкурентоспособны с ответами на Java ;-) Хотя по-прежнему интересно использовать.
Цифровая травма

Преобразование из простого унарного в десятичное дает неправильные ответы для унарного входного эквивалента десятичной формы X0X, например, 108. Ответственная за это строка /[;v]/!s/\b/0/2, которую необходимо изменить, чтобы /[;v]/!s:x\+:&0:она работала. Смотрите здесь .
Сешумара

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

Ссылка загружается правильно, но я ожидал чего-то другого, кроме серой страницы с надписью «TIO» и чего-то похожего на логотип Ubuntu - это то, что предназначено? И я имел в виду второй из ответов, на которые я ссылался ( 58007 ), поскольку именно здесь возникла простая унарная выборка.
Тоби Спейт

Ссылка TIO должна содержать исправленный код плюс пример ввода 108 в унарном формате. При запуске кода вы должны были видеть правильный результат 108, а не 180, как это было сгенерировано ранее этой фиксированной строкой кода. Обновление указанного ответа полностью зависит от вас. Это сообщество вики.
Сешумара

4

Как упоминалось в man sed(GNU), вы можете использовать любой символ в качестве разделителя для регулярных выражений, используя синтаксис

\%regexp%

где %заполнитель для любого персонажа.

Это полезно для таких команд, как

/^http:\/\//

которые короче как

\%^http://%

То, что упомянуто в руководстве GNU sed, но не в man sedтом, что вы можете изменить разделители s///и y///.

Например, команда

ss/ssg

удаляет все косые черты из пространства шаблона.


4

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


Разве это не мета-консенсус для sed, ссылающегося на простой старый унарный формат? У меня есть несколько ответов, где ввод в UCD мог бы помочь мне, если это так или иначе.
сешумара

@seshoumara Я имел в виду одинарный, а не UCD
Цифровая травма

Тогда преобразование из десятичного в простое старое унарное сэкономит вам 126 байтов в соответствии с тем ответом, который вы связали. 86 байтов предназначены для преобразования в UCD.
Сешумара

4

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

От десятичного до простого унарного: 102 + 1 (флаг r) = 103 байта. Я считал \tбуквальную вкладку, как 1 байт.

h
:
s:\w::2g
y:9876543210:87654321\t :
/ /!s:$:@:
/\s/!t
x;s:-?.::;x
G;s:\s::g
/\w/{s:@:&&&&&&&&&&:g;t}

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

Преимущество: он на 22 байта короче и, как дополнительный, работает с отрицательными целыми числами в качестве входных данных

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

От простого числа к десятичному: 102 + 1 (флаг r) = 103 байта

s:-?:&0:
/@/{:
s:\b9+:0&:
s:.9*@:/&:
h;s:.*/::
y:0123456789:1234567890:
x;s:/.*::
G;s:\n::
s:@::
/@/t}

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

Преимущество: это на 14 байтов короче. На этот раз обе подсказки работают для отрицательных целых чисел в качестве входных данных.

Недостаток: перезаписывает пространство удержания

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

Примером такого сложного ответа, где я создал и использовал эти фрагменты, является Взаимное число (1 / x) .


Для унарный к десятичной вы можете сохранить два байта, комбинируя последние две замены: s:\n|@$::g. tio.run/##K05N@f@/2ErX3krNwIpL30G/…
Иордания

У меня была своя попытка преобразования десятичных в унарные числа. Вот 97 байт :) Попробуйте онлайн! (также не требует -r, но с новым консенсусом флаги в любом случае не учитываются в счет байтаунта , и это не
портит

На самом деле, если вы измените последнюю строку с /\n/taна /\n/t, вы сохраните 1 байт, чтобы получить 96
Kritixi Lithos

@ Cowsquack Спасибо, 96 отлично! Не успеваю сейчас, посмотрю на это в эти выходные.
Сешумара

Конечно, тогда пришлите мне пинг в чате :)
Kritixi Lithos

3

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

Справочная страница для t:

Если a s///выполнила успешную замену с момента считывания последней строки ввода и с момента выполнения последней команды t или T, переходите к метке.

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

1{x;s/.*/0/;x}                   # initialize the counter to 0 in hold space
s/-/&/                           # check if number is negative
t increment_counter              # if so, jump to 'increment_counter' code block
b                                # else, do nothing (start a next cycle)

:increment_counter
#function code here

Выглядит хорошо, но это не так. Если первое число положительное, этот код все равно будет считать его отрицательным, поскольку переход, выполненный tдля первой строки ввода, выполняется независимо от того, что произошла успешная sзамена при инициализации счетчика! Правильно это: /-/b increment_counter.

Если это кажется легким, вы все равно можете быть одурачены при выполнении нескольких прыжков назад и вперед для имитации функций. В нашем примере increment_counterблок кода наверняка будет использовать много sкоманд. Возвращение назад b mainможет привести к тому, что другая проверка в «main» попадет в ту же ловушку. Вот почему я обычно возвращаюсь из блоков кода с s/.*/&/;t label. Это некрасиво, но полезно.


2

Вместо очистки пространства шаблона с s/.*//помощью zкоманды (в нижнем регистре), если вы используете GNU sed. Помимо меньшего числа байтов, он имеет то преимущество, что не запускает следующий цикл, как это dделает команда , что может быть полезно в определенных ситуациях.


1
Также может быть полезно, если у вас есть недопустимые многобайтовые последовательности (которые не совпадают .).
Тоби Спейт

2

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

Для десятичного в UCD я использую (68 байт; первый лучше всего размещен здесь 87 байт)

s/$/\n9876543210/
:a
s/\([1-9]\)\(.*\n.*\)\1\(.\)/\3x\2\1\3/
ta
P;d

UCD в десятичном формате (также 66 байтов; первый лучше всего размещен здесь 96)

s/$/\n0123456789/
:a      
s/\([0-8]\)x\(.*\n.*\)\1\(.\)/\3\2\1\3/
ta      
P;d
  • \nв замене не портативно. Вместо этого вы можете использовать другой символ и сохранить два байта, но вам потребуется больше байтов для удаления приложения вместо P;d; см. следующее замечание Или, если ваше пространство удержания пусто, обойтись G;s/$/9876543210/без байтового штрафа.
  • Если вам нужна дополнительная обработка, вам нужно больше байтов s/\n.*//вместо P;d.
  • Вы можете сохранить два байта каждый для этих старых sedверсий GNU с ошибками
  • Нет, вы не можете сохранить эти шесть обратных слешей, поскольку расширенные регулярные выражения не делают обратных ссылок

В этой ветке нет запятой для UCD и обратных преобразователей, которые запутывают пространство удержания или требуют неисправных версий sed.
Сешумара

Ваш собственный ответ от 6 апреля использует золотое пространство и будет работать только со старыми sedверсиями, которые нарушают стандарт POSIX.
Филиппос

Я не делаю десятичные преобразования в UCD! Прочитайте ветку еще раз внимательно. UCD означает, что 12 преобразуется в 0x0xx (что вычисляет ваш ответ), в то время как обычное унарное (что вычисляет мой ответ) означает, что 12 преобразуется в xxxxxxxxxxxx. Я выбрал @ как символ, но вы поняли идею. Более того, в PPCG не нужно придерживаться стандарта POSIX.
Сешумара

Если вам угодно, шериф
Филиппос

2

Прочитайте весь ввод сразу с -z

Часто вам нужно работать со всем вводом сразу, а не по одной строке за раз. Команда Nполезна для этого:

:
$!{N;b}

... но обычно вы можете пропустить это и использовать -zвместо этого флаг.

-zФлаг делает SED использования NUL ( \0) в качестве входной строки разделителя вместо \n, так что если вы знаете , что ваш вход не будет содержать \0, он будет читать весь вход сразу в качестве одной «линии»:

$ echo 'foo
> bar
> baz' | sed -z '1y/ao/eu/'
fuu
ber
bez

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


2

Добавить новую строку одним байтом

Команда Gдобавляет новую строку и содержимое пространства удержания в пространство образца, так что если ваше пространство удержания пусто, вместо этого:

s/$/\n/

Ты можешь сделать это:

G

Добавить новую строку в три байта

Команда Hдобавляет новую строку и содержимое пространства шаблона в пространство удержания и xменяет их местами, так что если ваше пространство удержания пусто, вместо этого:

s/^/\n/

Ты можешь сделать это:

H;x

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

H;z;x

1

В sed ближайшая к функции функция - это метка. Функция полезна, потому что вы можете выполнять ее код несколько раз, тем самым сохраняя много байтов. Однако в sed вам нужно будет указать метку возврата, и поэтому вы не можете просто вызывать эту «функцию» несколько раз по всему коду, как вы это делаете на других языках.

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

Пример, показывающий, что я имею в виду: взят из моего проекта, чтобы написать небольшую игру в sed

# after applying the player's move, I overwrite the pattern space with the flag "P"
s/.*/P/
b check_game_status
:continue_turn_from_player
#code

b calculate_bot_move
:return_bot_move
# here I call the same function 'check_game_status', but with a different flag: "B"
s/.*/B/
b check_game_status
:continue_turn_from_bot
#code (like say 'b update_screen')

:check_game_status   # this needs just the hold space to run
#code
/^P$/b continue_turn_from_player
/^B$/b continue_turn_from_bot

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


1

Пустые регулярные выражения эквивалентны ранее встреченному регулярному выражению

(спасибо Райли за то, что обнаружили это из анагольного представления )

Вот пример, где нам поручено создать 100 @ сек в пустом буфере.

s/$/@@@@@@@@@@/;s/.*/&&&&&&&&&&/ # 31 bytes
s/.*/@@@@@@@@@@/;s//&&&&&&&&&&/  # 30 bytes

Второе решение на 1 байт короче и использует тот факт, что пустые регулярные выражения заполняются последним найденным регулярным выражением. Здесь, для второй замены, последнее регулярное выражение было.* , поэтому здесь пустое регулярное выражение будет заполнено .*. Это также работает с регулярными выражениями в /conditionals/.

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

s/.*/@@@@@@@@@@/;/@*/!s/$/@/;s//&&&&&&&&&&/

Пустое регулярное выражение заполняется @*вместо, $потому что s/$/@/никогда не достигается.


Да, хороший ответ Я даже сделал регулярные выражения длиннее, чтобы их можно было снова подобрать (таким образом, программа стала короче).
Тоби Спейт

0

В основном бесполезный шаг:

y|A-y|B-z|

Это будет переводить только Aна Bи yк z(... и -к -;), но ничего больше, так

sed -e 'y|A-y|B-z|' <<<'Hello world!'

просто вернется:

Hello world!

Вы могли бы обеспечить это будет бесполезно, для образца, используя это на шестнадцатеричных значений нижнего регистра (содержащего только 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, eили f.)


2
Это то, что вы узнали трудным путем ?! ;-)
Тоби Спейт

Мне нравятся бесполезные сценарии: sed '; ;/s/b;y|A-y|B-z|;s ;s/ //; ; ;' <<<'Hello world'(Почему это не подавляет пространство?)
Ф. Хаури
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.