C (131 文字)
はい、13 1 !
main(c){for(;c=c?c:(c=toupper(getch())-32)?
"•ƒŒKa`^ZRBCEIQiw#S#nx(37+$6-2&@/4)'18=,*%.:0;?5"
[c-12]-34:-3;c/=2)putch(c/2?46-c%2:0);}
while
andfor
ループのロジックを 1 つのループに結合し、変数for
の宣言を入力パラメーターとして定義に移動することで、さらにいくつかの文字を探し出しました。この後者のテクニックは、ストレンジャーの別の課題への回答から借りました。c
main
GCC または ASCII のみのエディターでプログラムを検証しようとしている場合は、次の少し長いバージョンが必要になる場合があります。
main(c){for(;c=c?c:(c=toupper(getchar())-32)?c<0?1:
"\x95#\x8CKa`^ZRBCEIQiw#S#nx(37+$6-2&@/4)'18=,*%.:0;?5"
[c-12]-34:-3;c/=2)putchar(c/2?46-c%2:32);}
このバージョンは、次の変更により 17 文字長くなります (比較的大きな 148 文字)。
- +4:ポータブル
getchar()
でputchar()
ない代わりgetch()
にputch()
- +6: 非 ASCII 文字の代わりに 2 つの文字のエスケープ コード
- +1: 空白文字の場合は 0 ではなく 32
- +6:
c<0?1:
ASCII 32 未満の文字 (つまり から'\n'
) からのガベージを抑制するために " " を追加しました。!"#$%&'()*+[\]^_
`のいずれか{|}~
、またはASCII 126を超えるものからは、引き続きガベージが取得されます。
これにより、コードは完全に移植可能になります。コンパイル:
gcc -std=c89 -funsigned-char morse.c
は-std=c89
オプションです。ただし、が必要です。-funsigned-char
そうしないと、コンマとピリオドのゴミが表示されます。
135文字
c;main(){while(c=toupper(getch()))for(c=c-32?
"•ƒŒKa`^ZRBCEIQiw#S#nx(37+$6-2&@/4)'18=,*%.:0;?5"
[c-44]-34:-3;c;c/=2)putch(c/2?46-c%2:0);}
私の意見では、この最新バージョンは視覚的にもはるかに魅力的です。いいえ、移植性がなく、範囲外の入力に対して保護されなくなりました。また、UI がかなり悪く、1 文字ずつ入力してモールス符号に変換し、終了条件がありませんCtrl( +を押す必要がありますBreak)。しかし、優れた UI を備えた移植可能で堅牢なコードは必須ではありませんでした。
コードの可能な限り簡単な説明は次のとおりです。
main(c){
while(c = toupper(getch())) /* well, *sort of* an exit condition */
for(c =
c - 32 ? // effectively: "if not space character"
"•ƒŒKa`^ZRBCEIQiw#S#nx(37+$6-2&@/4)'18=,*%.:0;?5"[c - 44] - 34
/* This array contains a binary representation of the Morse Code
* for all characters between comma (ASCII 44) and capital Z.
* The values are offset by 34 to make them all representable
* without escape codes (as long as chars > 127 are allowed).
* See explanation after code for encoding format.
*/
: -3; /* if input char is space, c = -3
* this is chosen because -3 % 2 = -1 (and 46 - -1 = 47)
* and -3 / 2 / 2 = 0 (with integer truncation)
*/
c; /* continue loop while c != 0 */
c /= 2) /* shift down to the next bit */
putch(c / 2 ? /* this will be 0 if we're down to our guard bit */
46 - c % 2 /* We'll end up with 45 (-), 46 (.), or 47 (/).
* It's very convenient that the three characters
* we need for this exercise are all consecutive.
*/
: 0 /* we're at the guard bit, output blank space */
);
}
コード内の長い文字列の各文字には、1 つのテキスト文字のエンコードされたモールス符号が含まれています。エンコードされた文字の各ビットは、ダッシュまたはドットを表します。1 はダッシュを表し、0 はドットを表します。最下位ビットは、モールス符号の最初のダッシュまたはドットを表します。最後の「ガード」ビットは、コードの長さを決定します。つまり、エンコードされた各文字の最上位 1 ビットはコードの終わりを表し、出力されません。このガード ビットがないと、末尾にドットがある文字は正しく印刷されません。
たとえば、文字「L」は.-..
モールス信号の「 」です。これを 2 進数で表すには、最下位ビット 0010 から始まる 0、1、およびさらに 2 つの 0 が必要です。ガード ビットにもう 1 つ追加すると、符号化されたモールス符号が得られます: 10010、または 10 進数18. +34 オフセットを追加して、文字「4」の ASCII 値である 52 を取得します。したがって、エンコードされた文字配列には、33 番目の文字 (インデックス 32) として「4」があります。
この手法は、ACoolie の、strager の(2)、Miles の、pingw33n の、Alec の、およびAndrea のソリューションで文字をエンコードするために使用される手法と似ていますが、ビットごとに 2 つの演算 (シフト/除算) ではなく 1 つの演算 (シフト/除算) しか必要としないため、わずかに単純です。 /除算とデクリメント)。
編集:
残りの実装を読んでみると、 AlecとAnonが私より前にガード ビットを使用してこのエンコード方式を思いついたことがわかります。Anon のソリューションは特に興味深いもので、Alec と私が行ったように、ループ、AND、シフトするのではなく、 Python のbin
関数を使用し、"0b"
プレフィックスとガード ビットをで取り除きます。[3:]
おまけとして、このバージョンでは、ハイフン ( -....-
)、スラッシュ ( -..-.
)、コロン ( ---...
)、セミコロン ( -.-.-.
)、等号 ( -...-
)、およびアットマーク ( ) も処理され.--.-.
ます。8 ビット文字が許可されている限り、これらの文字をサポートするために追加のコード バイトは必要ありません。このバージョンでは、コードに長さを追加しない限り、これ以上文字をサポートできません (大なり小なり記号用のモールス符号がない限り)。
古い実装も興味深いものであり、テキストにはこのバージョンに当てはまる注意事項があるため、この投稿の以前の内容を以下に残しました。
わかりました、おそらく、ユーザー インターフェイスは最悪ですよね?そのため、 stragerから借りて、gets()
バッファリングされた、エコーされた行入力を提供する を、バッファリングされていない、エコーされていない文字入力を提供するに置き換えましgetch()
た。これは、入力したすべての文字が画面上で即座にモールス符号に変換されることを意味します。たぶんそれはクールです。標準入力でもコマンドライン引数でも機能しなくなりましたが、非常に小さいです。
ただし、参照用に古いコードを以下に残しておきます。これが新しいものです。
新しいコード、境界チェック付き、171 文字:
W(i){i?W(--i/2),putch(46-i%2):0;}c;main(){while(c=toupper(getch())-13)
c=c-19?c>77|c<31?0:W("œ*~*hXPLJIYaeg*****u*.AC5+;79-@6=0/8?F31,2:4BDE"
[c-31]-42):putch(47),putch(0);}
Enterループを中断し、プログラムを終了します。
新しいコード、境界チェックなし、159 文字:
W(i){i?W(--i/2),putch(46-i%2):0;}c;main(){while(c=toupper(getch())-13)
c=c-19?W("œ*~*hXPLJIYaeg*****u*.AC5+;79-@6=0/8?F31,2:4BDE"[c-31]-42):
putch(47),putch(0);}
以下は、古い 196/177 コードに従い、いくつかの説明があります。
W(i){i?W(--i/2),putch(46-i%2):0;}main(){char*p,c,s[99];gets(s);
for(p=s;*p;)c=*p++,c=toupper(c),c=c-32?c>90|c<44?0:W(
"œ*~*hXPLJIYaeg*****u*.AC5+;79-@6=0/8?F31,2:4BDE"[c-44]-42):
putch(47),putch(0);}
これはAndrea's Python answerに基づいており、モールス信号を生成するためにその回答と同じ手法を使用しています。しかし、エンコード可能な文字を次々に格納してそのインデックスを見つける代わりに、インデックスを次々に格納して文字ごとに検索します (以前の回答と同様に)。これにより、以前の実装者に問題を引き起こした、終わり近くの長いギャップが回避されます。
前と同じように、127 より大きい文字を使用しました。これを ASCII のみに変換すると、3 文字追加されます。長い文字列の最初の文字は に置き換える必要があります\x9C
。今回はオフセットが必要です。それ以外の場合、多数の文字が 32 未満であり、エスケープ コードで表す必要があります。
また、以前と同様に、stdin の代わりにコマンドライン引数を処理すると 2 文字が追加され、コード間に実スペース文字を使用すると 1 文字が追加されます。
一方、ここにある他のルーチンのいくつかは、[ ,.0-9\?A-Za-z] の許容範囲外の入力を処理しません。このような処理がこのルーチンから削除された場合、19 文字が削除され、合計で 177 文字まで減少する可能性があります。しかし、これが行われ、このプログラムに無効な入力が与えられると、クラッシュして燃える可能性があります。
この場合のコードは次のようになります。
W(i){i?W(--i/2),putch(46-i%2):0;}main(){char*p,s[99];gets(s);
for(p=s;*p;p++)*p=*p-32?W(
"œ*~*hXPLJIYaeg*****u*.AC5+;79-@6=0/8?F31,2:4BDE"
[toupper(*p)-44]-42):putch(47),putch(0);}