Rustでランレングスから始めよう。 [プログラミング]
前回Rustをランレングスを使ってみようとして、ランレングスってなんぞやというところで終わってしまった。Rubyのソースを丸のままコピーして手直しして動くようにした。
https://mi-chan-nel.com/run-length-encoding/
案外、Rubyと変わらないので、endとか添字アクセスとかを変えればある程度は動いた。
run_length.rs
ちょっと驚いたことに、&str型の文字列に添字アクセスできないということ。&strはプリミティブ型と言いながらも、文字列の何番目かにアクセスするためにメソッドを使う。それって本当にプリミティブ型と言えるのかよと思いながらググってみると、String型の参照と出ていた。そのものはプリミティブ型なのかもしれないが、実態はオブジェクトっぽい。なんか気持ち悪いな、おい。何にしても一般的に言われるようなプリミティブ的には扱えない。
https://qiita.com/aflc/items/f2be832f9612064b12c6
あとstr.chars().nth(i-1).unwrap() のところとか全然わかって使っていない。Rustはオブジェクト指向じゃないと思っていたが、がっつりオブジェクト指向ぽい。というか、ググってすぐに解決法は出てくるのはいいけど、本当はきちんと調べたほうがいいんだろうなぁ。まだどこにきちんとしたリファレンスがあるとか全然把握していない。
あとfor文の条件式には( )がいらないのな。コンパイラに
warning: unnecessary parentheses around `if` condition
って言われた。入れない言語もあったかと思うが、それもちょっと気持ち悪い。
ただ全般的にコンパイラのエラーがイミフである事が少ない。訳のわからないエラーメッセージはほとんどない。解決策すら示してくれる。きちんと英語が読めれば大体大丈夫だ。英語出てもすぐに読まないけどなw。
実行する。
でも、これでは最後のEがカウントされない。なぜだ?
結局、問題となるのが文字列の最後が\nなどで終端処理されていないっぽい。
そのため、最後の処理は文字列の長さで検知しないといけないか、明示的に文字列に\nを入れないといけない。
《後記》終端文字は\0でした。でも\nでも動くのでこのままにしておきます。こういう凡ミス結構するんだよなぁ…
最初の文に\nを加えるのでもいいんだけど、\nがない前提でソースを書き換えてみる。
ちょっとハマった。書き方が悪いのかもしれないけど、\nがないだけで簡潔に書けなくなった。思ったより\nで終端処理する意味って案外大きいのかもしれない。
あと、for文のカウンタはmutで宣言しなくていいのねとか。そもそもletすらないか…。
というか、コード構築力がなくて、Rubyのソースがなかったらここまですぐには書けなかった。というか、元々for文の添字とか細々と考えるの嫌いなんだけど、C言語みたいにめんどくさくなくなってfor inでかけて良いなと思った。でも、根本的なところでやっぱ面倒なんだよね、添字。
ランレングス自体の問題は、デコードする時にこの形式だと9以上連続すると2文字以上になって処理が面倒になってくるというところだ。連続する文字の後を8bitの値で保存するということも考えたが、それでも255バイトまでの連続しか表せないよなぁとか思ったり。
そもそもバイト列が連続するかどうか、というバイナリファイルでは特殊な状態のものが一般的ではない、ということでデコードは書かず、これ以上はランレングスは止めにしておく。FAXのG3の規格とかもやっぱり特殊と言わざるを得ないしね。データの圧縮としては、膨張する可能性も大きいということで、とりあえずやったというところで止めておく。
実際にパソコンで使われているランレングスと言えば、BMP形式のファイルでRLEってのがあったなぁと思い出した。
https://ruche-home.net/program/bmp/rle
でも、今更BMPもないだろうと思ったし、そもそもmac上でやっているのでBMPは一般的ではないと思った。BMPは基本的にWindowsのフォーマットだと思うし。macはpictだっけ? 今となっては圧縮なしの生データみたいなフォーマットはないんだろうな。昔と違って圧縮伸長処理が瞬間でできるだろうし。
そんなわけでランレングスはこれ以上はあまり益がないのでやりません。とりあえず概念だけでもいいかなと。
今、エディタはVSCodeでRustコードを書いているのだけれども、デバッグ機能とかを入れようとするとHomebrewのRustを使えないっぽいので、結局動作とかをターミナルから実行しています。それでも普通なんだろうけど、VSCodeからできるならやりたいじゃないですか。でもできないんだよな。
PHPでもすごく苦労したけど、設定が明確ではないのがキツすぎる。状況によって違うんだよな。大体、本家が作っているわけでもないので、細かいところが行き届いていない感じ。VSCodeはMSとしてはそこそこ良いプロダクトだと思うけど、あまりにOSS的に分散しすぎている感があって、うまく動かないケースが多すぎる気がする。ただ単に日本語対応エディタとして、Linux上のファイルをいじるとかだと問題ないし便利なんだけどね。デバッガは外付けでやろうとするとかなり厳しいのかも。
https://mi-chan-nel.com/run-length-encoding/
案外、Rubyと変わらないので、endとか添字アクセスとかを変えればある程度は動いた。
run_length.rs
fn main() { let str = "AAAAAAEEEEFFFFFFDGGGGGGGSSSSSSAAAE"; println!("{}",str); let mut count = 0; for i in 1..(str.len()) { if str.as_bytes()[i-1] == str.as_bytes()[i] { count = count + 1 }else{ print!("{}{}",str.chars().nth(i-1).unwrap(),count+1); count = 0; } } println!(); }
ちょっと驚いたことに、&str型の文字列に添字アクセスできないということ。&strはプリミティブ型と言いながらも、文字列の何番目かにアクセスするためにメソッドを使う。それって本当にプリミティブ型と言えるのかよと思いながらググってみると、String型の参照と出ていた。そのものはプリミティブ型なのかもしれないが、実態はオブジェクトっぽい。なんか気持ち悪いな、おい。何にしても一般的に言われるようなプリミティブ的には扱えない。
https://qiita.com/aflc/items/f2be832f9612064b12c6
あとstr.chars().nth(i-1).unwrap() のところとか全然わかって使っていない。Rustはオブジェクト指向じゃないと思っていたが、がっつりオブジェクト指向ぽい。というか、ググってすぐに解決法は出てくるのはいいけど、本当はきちんと調べたほうがいいんだろうなぁ。まだどこにきちんとしたリファレンスがあるとか全然把握していない。
あとfor文の条件式には( )がいらないのな。コンパイラに
warning: unnecessary parentheses around `if` condition
って言われた。入れない言語もあったかと思うが、それもちょっと気持ち悪い。
ただ全般的にコンパイラのエラーがイミフである事が少ない。訳のわからないエラーメッセージはほとんどない。解決策すら示してくれる。きちんと英語が読めれば大体大丈夫だ。英語出てもすぐに読まないけどなw。
実行する。
AAAAAAEEEEFFFFFFDGGGGGGGSSSSSSAAAE A6E4F6D1G7S6A3
でも、これでは最後のEがカウントされない。なぜだ?
結局、問題となるのが文字列の最後が\nなどで終端処理されていないっぽい。
そのため、最後の処理は文字列の長さで検知しないといけないか、明示的に文字列に\nを入れないといけない。
《後記》終端文字は\0でした。でも\nでも動くのでこのままにしておきます。こういう凡ミス結構するんだよなぁ…
let str = "AAAAAAEEEEFFFFFFDGGGGGGGSSSSSSAAAE\n";
最初の文に\nを加えるのでもいいんだけど、\nがない前提でソースを書き換えてみる。
fn main() { let str = "AAAAAAEEEEFFFFFFDGGGGGGGSSSSSSAAAE"; println!("{}",str); let mut count = 0; for i in 1..(str.len()) { if str.as_bytes()[i-1] == str.as_bytes()[i] { count = count + 1; }else{ print!("{}{}",str.chars().nth(i-1).unwrap(),count+1); count = 0; } if i == str.len() -1 { print!("{}{}",str.chars().nth(i).unwrap(),count+1); } } println!(); }
ちょっとハマった。書き方が悪いのかもしれないけど、\nがないだけで簡潔に書けなくなった。思ったより\nで終端処理する意味って案外大きいのかもしれない。
あと、for文のカウンタはmutで宣言しなくていいのねとか。そもそもletすらないか…。
というか、コード構築力がなくて、Rubyのソースがなかったらここまですぐには書けなかった。というか、元々for文の添字とか細々と考えるの嫌いなんだけど、C言語みたいにめんどくさくなくなってfor inでかけて良いなと思った。でも、根本的なところでやっぱ面倒なんだよね、添字。
ランレングス自体の問題は、デコードする時にこの形式だと9以上連続すると2文字以上になって処理が面倒になってくるというところだ。連続する文字の後を8bitの値で保存するということも考えたが、それでも255バイトまでの連続しか表せないよなぁとか思ったり。
そもそもバイト列が連続するかどうか、というバイナリファイルでは特殊な状態のものが一般的ではない、ということでデコードは書かず、これ以上はランレングスは止めにしておく。FAXのG3の規格とかもやっぱり特殊と言わざるを得ないしね。データの圧縮としては、膨張する可能性も大きいということで、とりあえずやったというところで止めておく。
実際にパソコンで使われているランレングスと言えば、BMP形式のファイルでRLEってのがあったなぁと思い出した。
https://ruche-home.net/program/bmp/rle
でも、今更BMPもないだろうと思ったし、そもそもmac上でやっているのでBMPは一般的ではないと思った。BMPは基本的にWindowsのフォーマットだと思うし。macはpictだっけ? 今となっては圧縮なしの生データみたいなフォーマットはないんだろうな。昔と違って圧縮伸長処理が瞬間でできるだろうし。
そんなわけでランレングスはこれ以上はあまり益がないのでやりません。とりあえず概念だけでもいいかなと。
今、エディタはVSCodeでRustコードを書いているのだけれども、デバッグ機能とかを入れようとするとHomebrewのRustを使えないっぽいので、結局動作とかをターミナルから実行しています。それでも普通なんだろうけど、VSCodeからできるならやりたいじゃないですか。でもできないんだよな。
PHPでもすごく苦労したけど、設定が明確ではないのがキツすぎる。状況によって違うんだよな。大体、本家が作っているわけでもないので、細かいところが行き届いていない感じ。VSCodeはMSとしてはそこそこ良いプロダクトだと思うけど、あまりにOSS的に分散しすぎている感があって、うまく動かないケースが多すぎる気がする。ただ単に日本語対応エディタとして、Linux上のファイルをいじるとかだと問題ないし便利なんだけどね。デバッガは外付けでやろうとするとかなり厳しいのかも。
タグ:RUST
2021-12-06 10:46
コメント(0)
コメント 0