sedでのゴルフのヒント


19

sedでゴルフをするための一般的なヒントは何ですか?コードゴルフの問題に適用でき、sedに少なくともある程度固有のアイデアを探しています(たとえば、「コメントの削除」は答えではありません)。

回答ごとに1つのヒントを投稿してください。


4
そうでもないゴルフの先端(しかし、ゴルフのために、まだヒント):あなたのコードの短いを保つことができるので、改行は、ちょうどセミコロンなど多くのバイトとして消費読めます。
デニス

ヒントでもありませんが、問題です。GNUsedを使用していますが、Fコマンドは機能しませんでした。誰が理由を知っていますか?
seshoumara

@seshoumara Fは私のGNU sed(Debianテスト)で動作します。-もちろん、stdinから読み込んだ場合は印刷されますが、それは当然のことです。何から得sed -e 'F;Q' /etc/hostnameますか?
トビー・スペイト

@TobySpeightこのエラーが発生します:char 1: unknown command: F。多分sedを更新する必要があります。どのバージョンがありますか?Lまた、このコマンドは動作しませんが、以来、それは無用とにかくだ-l nが存在します。GNU sedのサイトで言及されている他のすべては機能します。
seshoumara

1
bash, sed and dcこれらの言語について話したいと思う人のためにチャットルームを開きました。コミュニティを作りましょう!
seshoumara

回答:


11

ラベルを使用する必要がある場合は、ラベル名をできるだけ短くする必要があります。実際、極端にとると、空の文字列をラベル名として使用することさえできます。

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

4
gnu sed 4.3以降、この動作は削除されました:ラベルが必要になりました。
ケビン

実際、実際のgit commit リンクもここにあります。PPCGの場合、GNU sed 4.2.xの回答を投稿することは許可されているため、これはあまり変わらないでしょうが、残念ながら、このトリックは公式には機能しなくなることを知っておくと良いでしょう。
seshoumara

8

GNU sedのドキュメントでは説明sのように、コマンド「のsedのスイスアーミーナイフを」。ただし、1つの文字のすべてのインスタンスを別の文字に置き換えるだけの場合は、yコマンドが必要です。

y/a/b/

以下よりも1文字短いです。

s/a/b/g

そのまた道より速く、所定の位置に文字を入れ替えることができます:y/12/21/
mikeserv

6

拡張正規表現構文(GNU sed)の使用を検討してください。この-rオプションはスコアリングに1バイトかかりますが、1回使用するだけで1組のバックスラッシュを排除でき\(...\)ます。


2
追加の注意事項は、-rGNU sed固有のものと思われます。
マナトワーク

@manat-追加(ただし、コミュニティWikiの回答なので、自分で編集することもできます)。
トビースパイト

もちろん。私はそれをヒントの一部とは考えず、追加のメモだけを考えました。
マナトワーク

また、バックスラッシュも必要ないため、正規表現の一致で、、およびを使用する+場合?、それ自体に支払いを続けます。{}|
seshoumara

-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以降では、このバグは残念ながら修正されました。こちらをご覧ください
seshoumara

5

組み込みの算術演算はありませんが、計算は単項または単項コード化された10進数で実行できます。次のコードは、10進数を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

そして、10進数に戻す変換を次に示します。

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

これらは両方とも「数値を使用せずに2つの数値を乗算する」という回答から取得されます。

この答えから「{Curly Numbers};」へのループのこのペアを使用して、単純な古い単項を変換できます、単位は;です。私が使ってきたvxのためにローマに一致するように5して10b「ビス」から来ます。

# 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の答えにまだ競争力があるかもしれませんが、コードゴルフをほぼ間違いなく失っています;-)それでも使用するのはまだ楽しいです。
デジタル外傷

単純な単項から10進数への変換は/[;v]/!s/\b/0/2、108などの10進形式X0Xに相当する単項入力に対して誤った答えを返します/[;v]/!s:x\+:&0:。こちらをご覧ください
seshoumara

@seshoumara、あなたのリンクは空のページのようです。しかし、参照された回答からそのコードを抽出するときにエラーを犯したことは完全に妥当であるため、修正を適用します。
トビースパイト

リンクは正しく読み込まれますが、「TIO」とUbuntuロゴのように見える灰色のページ以外のものを期待していました-それは意図したものですか?そして、私が参照した2番目の回答(58007)について言及していました。これは、単項単項サンプルの起源であるためです。
トビーSpeight

TIOリンクには、修正されたコードに加えて、108の単項入力が含まれているはずです。コードを実行すると、180番ではなく108番の正しい結果が表示されるはずです。これは、現在修正されたコード行によって以前に生成されたものです。参照された回答の更新は完全にあなた次第です。これはコミュニティwikiです。
seshoumara

4

man sed(GNU)で述べたように、次の構文を使用して、正規表現の区切り文字として任意の文字を使用できます

\%regexp%

where %は、任意のキャラクターのプレースホルダーです。

これは次のようなコマンドに役立ちます

/^http:\/\//

短い

\%^http://%

何に記載されているGNUマニュアルのsedが、ないでは、man sedあなたがの区切り文字を変更することができるということであるs///y///同様。

たとえば、コマンド

ss/ssg

パターンスペースからすべてのスラッシュを削除します。


4

質問によって明示的に禁止されていない場合、このメタ質問のコンセンサスは、数値入力が単項である可能性があるということです。これにより、この回答のとおり、86バイトの10進数が単項に保存されます。


sedのメタコンセンサスは、単純な古い単項形式に言及していませんか?どちらにしても、UCDでの入力が助けになるいくつかの答えがあります。
seshoumara

@seshoumara私はUCD、単項ない意味
デジタルトラウマ

次に、10進数から単純な古い単項への変換により、リンクした回答ごとに126バイト節約できます。86バイトはUCDへの変換用です。
seshoumara

4

このヒントの回答を拡張して、10進数と単純な単項数値形式との間の変換に関して、次の代替方法とその長所と短所を紹介します。

10進数から単純な単項: 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バイト短くなり、入力として負の整数で機能します

欠点:ホールドスペースが上書きされます。ただし、プログラムの開始時に入力整数を変換する必要がある可能性が高いため、この制限はほとんど感じられません。

単項から10進数へのプレーン: 102 + 1(rフラグ)= 103バイト

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

オンラインでお試しください!

利点:14バイト短くなります。今回は、両方のtipバージョンが入力として負の整数に対して機能します。

欠点:ホールドスペースが上書きされます

複雑な課題の場合、これらのスニペットを変換して、変換する数値に加えて、パターンスペースまたはホールドスペースに存在する可能性がある他の情報を操作する必要があります。正の数のみを使用する場合、またはゼロだけでは有効な入力/出力にならないことがわかっている場合は、コードをさらにゴルフにかけることができます。

これらのスニペットを作成して使用したそのようなチャレンジ回答の例は、数値逆数(1 / x)です。


単項から10進数の場合、最後の2つの置換を組み合わせることで2バイトを節約できますs:\n|@$::gtio.run/##K05N@f@/2ErX3krNwIpL30G/…–
ヨルダン

小数から単項への変換器を自分で試してみました。97バイトです:) オンラインで試してみてください!(これも必要ありませんが-r、新しいコンセンサスでは、フラグはバイトカウントにカウントされず、ホールドスペースを台無しにしません)
Kritixi Lithos

実際、最後の行をから/\n/taに変更すると/\n/t、1バイトを節約して96を取得します
Kritixi Lithos

@Cowsquackありがとう、96は素晴らしい!今は時間がないので、今週末に調べます。
seshoumara

確かに、チャットでpingを送ってください:)
Kritixi Lithos

3

コマンドtTコマンドについて説明しましょう。それらはマニュアルページで説明されていますが、特にコードが複雑になった場合、それを忘れて誤ってバグを導入するのは簡単です。

のマニュアルページステートメントt

s///最後の入力行が読み取られてから、また最後のtまたはTコマンド以降にa が置換に成功した場合、labelに分岐します。

意味を示す例:数字のリストがあり、ネガがいくつあるかを数えたいとします。以下の部分的なコード:

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

GNU sedをs/.*//使用する場合は、パターンスペースをクリアする代わりに、zコマンド(小文字)を使用します。バイト数が少ないことに加えて、コマンドのように次のサイクルを開始しないという利点がdあります。これは特定の状況で役立つ場合があります。


1
また、無効なマルチバイトシーケンス(に一致しない.)がある場合にも役立ちます。
トビー・スペイト

2

私はこれが古いスレッドであることを知っていますが、ほぼ100バイトの10進のUCDコンバーターへの不格好な10進を見つけましたsed

UCD 10進 Iの使用(68のバイト;元最高はここに掲載87バイト)

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

UCDから10進数への変換も(66バイト。前者がここに最もよく投稿されている96)

s/$/\n0123456789/
:a      
s/\([0-8]\)x\(.*\n.*\)\1\(.\)/\3\2\1\3/
ta      
P;d
  • \n交換でポータブルではありません。代わりに別の文字を使用して2バイトを保存できますが、付録ではなくP;d; を削除するには、さらにバイトが必要になります。次の発言を参照してください。または、ホールドスペースが空の場合、G;s/$/9876543210/バイトペナルティなしで実行します。
  • さらに処理が必要な場合は、のs/\n.*//代わりにさらにバイトが必要になりますP;d
  • これらのバグのある古いGNU sedバージョンでは、それぞれ2バイト節約できます
  • いいえ、拡張正規表現は後方参照を行わないため、これらの6つのバックスラッシュを保存することはできません

このスレッドには、ホールドスペースを混乱させたり、不良なsedバージョンを必要とするUCDやバックコンバーターへの10進数はありません。
seshoumara

4月6日からのあなた自身の答えはゴールドスペースを使用sedし、POSIX標準に違反する古いバージョンでのみ実行されます。
フィリポス

10進数からUCDへの変換は行っていません!スレッドを注意深く読んでください。UCDは12が0x0xx(あなたの答えが計算するもの)に変換されることを意味し、一方、単項(私の答えが計算するもの)は12がxxxxxxxxxxxxに変換されることを意味します。@をシンボルとして選択しましたが、あなたはそのアイデアを理解します。さらに、PPCGでは、POSIX標準に準拠する必要はありません。
seshoumara

喜ばれるなら、保安官
フィリポス

2

で入力全体を一度に読む -z

多くの場合、一度に1行ではなく、入力全体を一度に操作する必要があります。このNコマンドは次の場合に便利です。

:
$!{N;b}

...ただし、通常はスキップして、-z代わりにフラグを使用できます。

-zフラグは、sedを使用NULを(作る\0その入力行区切りとして)の代わりに、\nあなたの入力が含まれています知っていればそう、\0それは一つの「行」として、一度にすべての入力を読み込みます。

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

オンラインでお試しください!


2

改行を1バイトで追加します

このGコマンドは、改行とホールドスペースの内容をパターンスペースに追加します。そのため、ホールドスペースが空の場合は、この代わりに:

s/$/\n/

あなたはこれを行うことができます:

G

改行を3バイトで追加します

このHコマンドは、改行とパターンスペースの内容をホールドスペースに追加しx、2つをスワップします。そのため、ホールドスペースが空の場合は、この代わりに:

s/^/\n/

あなたはこれを行うことができます:

H;x

これにより、ホールドスペースが汚染されるため、1回しか機能しません。ただし、さらに2バイトの場合、スワッピングの前にパターンスペースをクリアできますが、それでも2バイトの節約になります。

H;z;x

1

sedでは、機能に最も近いものはラベルです。関数は、コードを複数回実行できるため、多くのバイトを節約できるため便利です。ただし、sedでは戻りラベルを指定する必要があるため、他の言語で行うようにコード全体でこの「関数」を単純に複数回呼び出すことはできません。

私が使用する回避策は、2つのメモリのうちの1つにフラグを追加することです。フラグは、戻りラベルを選択するために使用されます。これは、機能コードが単一のメモリ空間(他のメモリ空間)のみを必要とする場合に最適に機能します。

私の言いたいことを示す例: 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文字にゴルフする必要があります。説明をわかりやすくするためにフルネームを使用しました。


1

空の正規表現は、以前に検出された正規表現と同等です

アナゴルの提出からこれを発見してくれたライリーに感謝します)

これは@、空のバッファに100を作成するというタスクの例です。

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

2番目の解決策は1バイト短く、空の正規表現が最後に検出された正規表現で埋められるという事実を使用します。ここで、2番目の置換の最後の正規表現は.*であったため、ここの空の正規表現はで埋められ.*ます。これは、の正規表現でも機能し/conditionals/ます。

これは以前に検出された正規表現であるため、以下も機能することに注意してください。

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

空の正規表現には到達しないため、@*代わりに埋められます。$s/$/@/


はい、良い答えです。正規表現をさらに長くして、このように再照合できるようにしました(したがって、プログラムが短くなります)。
トビー・スペイト

0

ほとんど役に立たないステップ:

y|A-y|B-z|

これは翻訳しないだろうAByz(...と-する-ので、それ以外は何も;)

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

戻るだけです:

Hello world!

あなたは(のみを含む小文字の16進値でこれを使用して、このサンプルのために、役に立たないであろう保証ができ0123456789abcdeまたはf)。


2
これはあなたが難しい方法を見つけたものですか?!;-)
トビー・スペイト

役に立たないスクリプトが好きです:(sed '; ;/s/b;y|A-y|B-z|;s ;s/ //; ; ;' <<<'Hello world'なぜこれがスペースを抑制しないのですか?)
F. Hauri
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.