2024/02/14(水) [n年前の日記]
#1 [basic] FreeBASICでsplit()を使いたい
プログラミング言語の Perl や Ruby や Python には split() というメソッドがある。これを使うと、指定した区切り文字で、文字列を分割して配列にしてくれる。かなり便利。
FreeBASIC でもsplit() を使いたい。しかし、標準では持ってない。どうにかできんのか。いや、自分で書くしかないだろうけど。ということで、そのあたりをググって調べてみた。
環境は Windows10 x64 22H2 + FreeBASIC 1.10.1 32bit。
FreeBASICでsplit()を使いたいという需要はちょくちょくあるようで、公式掲示板でも色々な実装事例が紹介されてた。
_function Split - freebasic.net
_function Split - Page 2 - freebasic.net
_Split String Algorithm for FreeBasic - freebasic.net
_Sugesstion String Split in FB - freebasic.net
_Easy Split Function - freebasic.net
_I need someone to defeat my string splitting algo - freebasic.net
色々なやり方はあるけれど、個人的には、C言語の strtok() を利用して実装してしまうのが簡単そうに見えた。
_C Standard Library Functions - FreeBASIC Wiki Manual | FBWiki
_strtokによるトークンの切り出し ・ ソフトウェアII
_C/C++にsplit関数はなく、代わりにstrtok関数を使う|情報科学を学ぶ大学生のブログ
_<紙>さんLoG FreeBASIC 学習:strtok, 文字列を指定文字で分割
ただ、strtok() は、文字列の中で区切り文字が見つかったら、そこに文字列の終端記号である 0 を書き込んで処理をするらしい。なんだか怖い…。元の文字列のあちこちに終端記号が書き込まれて、元文字列がズタズタになりそうな…。
FreeBASIC でもsplit() を使いたい。しかし、標準では持ってない。どうにかできんのか。いや、自分で書くしかないだろうけど。ということで、そのあたりをググって調べてみた。
環境は Windows10 x64 22H2 + FreeBASIC 1.10.1 32bit。
FreeBASICでsplit()を使いたいという需要はちょくちょくあるようで、公式掲示板でも色々な実装事例が紹介されてた。
_function Split - freebasic.net
_function Split - Page 2 - freebasic.net
_Split String Algorithm for FreeBasic - freebasic.net
_Sugesstion String Split in FB - freebasic.net
_Easy Split Function - freebasic.net
_I need someone to defeat my string splitting algo - freebasic.net
色々なやり方はあるけれど、個人的には、C言語の strtok() を利用して実装してしまうのが簡単そうに見えた。
_C Standard Library Functions - FreeBASIC Wiki Manual | FBWiki
_strtokによるトークンの切り出し ・ ソフトウェアII
_C/C++にsplit関数はなく、代わりにstrtok関数を使う|情報科学を学ぶ大学生のブログ
_<紙>さんLoG FreeBASIC 学習:strtok, 文字列を指定文字で分割
ただ、strtok() は、文字列の中で区切り文字が見つかったら、そこに文字列の終端記号である 0 を書き込んで処理をするらしい。なんだか怖い…。元の文字列のあちこちに終端記号が書き込まれて、元文字列がズタズタになりそうな…。
◎ strtok()で試してみた :
本当に strtok() を使って split() 相当を実装できるのか試してみた。
_strtok_test.bas
fbc strtok_test.bas でコンパイル。実行結果は以下。
ちゃんと分割できているように見える。区切り文字として扱う空白が連続して入っていても、イイ感じに処理してくれた。
少し解説。FreeBASIC でC言語が持ってる関数を使いたい場合は、#include "crt.bi" を最初のほうで入れておく。
配列の長さ(数?)を可変にしたい時は、ReDim を使う。
ReDim を使う際の注意。ReDim preserve とすれば、それまで格納した値を保持したまま長さを変更してくれるけど、preserve をつけないとそれまで格納した値を全部クリアした状態で配列の長さを変更してしまう。自分、格納した値が全部消えてるから変だなおかしいなと悩んでたら、単に preserve をつけるのを忘れてたという…。
UBound() を使うと、その配列変数の最後の添え字(?)、配列のインデックスの最大値を取得できる。
_strtok_test.bas
#include "crt.bi" Sub Split(byref text As String, byref delim As String, result() as String) var p = strtok(strptr(text), strptr(delim)) While (p) ReDim preserve result(UBound(result) + 1) result(UBound(result)) = *p p = strtok(NULL, strptr(delim)) Wend End Sub ' main Dim As String text = "this is a test" Dim words() As String split(text, " ", words()) Print text For i As Integer = 0 To UBound(words) Print "[" & words(i) & "]" Next i Print " ...success."
fbc strtok_test.bas でコンパイル。実行結果は以下。
> strtok_test.exe this is a test [this] [is] [a] [test] ...success.
ちゃんと分割できているように見える。区切り文字として扱う空白が連続して入っていても、イイ感じに処理してくれた。
少し解説。FreeBASIC でC言語が持ってる関数を使いたい場合は、#include "crt.bi" を最初のほうで入れておく。
配列の長さ(数?)を可変にしたい時は、ReDim を使う。
ReDim を使う際の注意。ReDim preserve とすれば、それまで格納した値を保持したまま長さを変更してくれるけど、preserve をつけないとそれまで格納した値を全部クリアした状態で配列の長さを変更してしまう。自分、格納した値が全部消えてるから変だなおかしいなと悩んでたら、単に preserve をつけるのを忘れてたという…。
UBound() を使うと、その配列変数の最後の添え字(?)、配列のインデックスの最大値を取得できる。
◎ split()では解決しなかった :
ひとまず split() を使えばどうにかなるだろうと思ってたけど、ちと考えが甘かった。
例えば、以下のような文字列なら、split() で十分処理できそうなのだけど…。
以下のような文字列ではよろしくない。
お判りいただけるだろうか。「face="DejaVu Sans"」と区切ってほしいけれど、「face="DejaVu」と「Sans"」になってしまっている。間に区切り文字の空白があるから当たり前だけど。
こういう事例にも対応できるような処理を書くしかないか…。
例えば、以下のような文字列なら、split() で十分処理できそうなのだけど…。
char id=32 x=250 y=22 width=5 height=5 xoffset=-2 yoffset=21 xadvance=7 page=0 chnl=15
> strtok_test3.exe char id=32 x=250 y=22 width=5 height=5 xoffset=-2 yoffset=21 xadvance=7 page=0 chnl=15 [char] [id=32] [x=250] [y=22] [width=5] [height=5] [xoffset=-2] [yoffset=21] [xadvance=7] [page=0] [chnl=15] ...success.
以下のような文字列ではよろしくない。
info face="DejaVu Sans" size=24 bold=1 italic=0 charset="ANSI" unicode=0 stretchH=100 smooth=1 aa=4 padding=0,0,0,0 spacing=1,1 outline=2
> strtok_test3.exe info face="DejaVu Sans" size=24 bold=1 italic=0 charset="ANSI" unicode=0 stretchH=100 smooth=1 aa=4 padding=0,0,0,0 spacing=1,1 outline=2 [info] [face="DejaVu] [Sans"] [size=24] [bold=1] [italic=0] [charset="ANSI"] [unicode=0] [stretchH=100] [smooth=1] [aa=4] [padding=0,0,0,0] [spacing=1,1] [outline=2] ...success.
お判りいただけるだろうか。「face="DejaVu Sans"」と区切ってほしいけれど、「face="DejaVu」と「Sans"」になってしまっている。間に区切り文字の空白があるから当たり前だけど。
こういう事例にも対応できるような処理を書くしかないか…。
◎ split()ぐらい標準でつけてほしい :
思考メモ。
FreeBASICの公式掲示板を眺めてたら、「split()が欲しい。標準でつけてくれ」という要望に対して、「俺なら数行のコードで実現できるぞ。だからそんなもん要らねえ」と言い出した人を見かけた。個人的にかなり呆れてしまった。お前のマウンティングで皆が楽になるルートを潰してんじゃねえよ…みたいな。
こんな処理は各人が毎回独自に実装して用意するより標準で持ってたほうがいいに決まってる。どうして他の言語が組み込みで持ってるのかを考えたら…。Perl や Ruby や Python や Java や JavaScript や Go言語が「split」のたった5文字で済ませてることを、FreeBASIC では毎回実処理コードをどこかに書かなきゃいけないとか、そしてそれを当たり前のこととして利用者全員に強制するとかクソ過ぎる…。そういうところが「塵も積もれば」的に効いてきて最後には無駄に長くてゲンナリするソースばかりが目につくようになってプログラミング言語としての魅力も薄れて誰も触らなくなるわけで…。
既に標準状態で山のような .bi が inc/ の中に入ってるんだから、「文字列処理をしたいならコレを include すると楽だよ。ただし速度は期待するな。もっと速いのが欲しかったらその時は自分で書け」ぐらいの感覚で .bi を一つ追加すれば済む話だろうに。いやまあ、テストがどうとか速度がどうとか言い出して標準ライブラリとして加えることをとにかく面倒臭がってる気配も感じたのでその手の .bi が追加されるのは今後も望み薄かもしれないけれど。
そのあたりを考えてるうちに、Python の pip、Ruby の gem、Perl のCPAN等々はよく考えられているなと思えてきた。「こういうライブラリが必要だな」となったらコマンド一つでライブラリをインストールできてしまう。もし、そういう状況が用意されているなら、標準ライブラリで持たなくてもまあいいかな、とも思えてくる。しかし、FreeBASIC の場合はそういうツールが無いのだから、最初から標準で色々入れておくしかないだろうと思うのだけど。
まあ、今の時代にBASIC言語を名乗るソレにどうこう言ってみても、というところもあるのだけど…。
一発で exe が作れて、しかも処理速度がそこそこ速い点に魅力を感じたから FreeBASIC を触ってみているけれど、フツーは Python あたりを使うよな…。あらゆるOSにPythonが標準でインストールされてたらいいのに…。いや、それはそれでPythonのバージョンの違いで余計なトラブルが起きそう…。
思考メモです。オチは無いです。
2024/02/15追記。安易に「.biを1つ追加すれば」などと書いてしまったけれど。考えてみたらマルチバイト文字列への対応が面倒なのではと思えてきた…。
FreeBASICの公式掲示板を眺めてたら、「split()が欲しい。標準でつけてくれ」という要望に対して、「俺なら数行のコードで実現できるぞ。だからそんなもん要らねえ」と言い出した人を見かけた。個人的にかなり呆れてしまった。お前のマウンティングで皆が楽になるルートを潰してんじゃねえよ…みたいな。
こんな処理は各人が毎回独自に実装して用意するより標準で持ってたほうがいいに決まってる。どうして他の言語が組み込みで持ってるのかを考えたら…。Perl や Ruby や Python や Java や JavaScript や Go言語が「split」のたった5文字で済ませてることを、FreeBASIC では毎回実処理コードをどこかに書かなきゃいけないとか、そしてそれを当たり前のこととして利用者全員に強制するとかクソ過ぎる…。そういうところが「塵も積もれば」的に効いてきて最後には無駄に長くてゲンナリするソースばかりが目につくようになってプログラミング言語としての魅力も薄れて誰も触らなくなるわけで…。
既に標準状態で山のような .bi が inc/ の中に入ってるんだから、「文字列処理をしたいならコレを include すると楽だよ。ただし速度は期待するな。もっと速いのが欲しかったらその時は自分で書け」ぐらいの感覚で .bi を一つ追加すれば済む話だろうに。いやまあ、テストがどうとか速度がどうとか言い出して標準ライブラリとして加えることをとにかく面倒臭がってる気配も感じたのでその手の .bi が追加されるのは今後も望み薄かもしれないけれど。
そのあたりを考えてるうちに、Python の pip、Ruby の gem、Perl のCPAN等々はよく考えられているなと思えてきた。「こういうライブラリが必要だな」となったらコマンド一つでライブラリをインストールできてしまう。もし、そういう状況が用意されているなら、標準ライブラリで持たなくてもまあいいかな、とも思えてくる。しかし、FreeBASIC の場合はそういうツールが無いのだから、最初から標準で色々入れておくしかないだろうと思うのだけど。
まあ、今の時代にBASIC言語を名乗るソレにどうこう言ってみても、というところもあるのだけど…。
一発で exe が作れて、しかも処理速度がそこそこ速い点に魅力を感じたから FreeBASIC を触ってみているけれど、フツーは Python あたりを使うよな…。あらゆるOSにPythonが標準でインストールされてたらいいのに…。いや、それはそれでPythonのバージョンの違いで余計なトラブルが起きそう…。
思考メモです。オチは無いです。
2024/02/15追記。安易に「.biを1つ追加すれば」などと書いてしまったけれど。考えてみたらマルチバイト文字列への対応が面倒なのではと思えてきた…。
[ ツッコむ ]
#2 [digital] 親父さんがワイヤレススピーカーを購入
親父さんが、首に引っ掛けるタイプのワイヤレススピーカーを購入したらしい。しかし、「音が全然聞こえない」「TVの音が聞こえない」と騒ぎ始めた。
購入した製品の型番は、audio-technica AT-NSP300BT。
_AT-NSP300BT|AVアクセサリー:スピーカー|オーディオテクニカ
説明書を見たら、予想通り、Bluetooth接続のワイヤレススピーカーだった。ウチの茶の間に置いてあるTVは、TOSHIBA REGZA Z9000 という古い製品なので、Bluetooth送信機能なんてついてるはずもなく。親父さんに、「貴方は送信機を持ってないのに、今回受信機だけを買ってしまったんですよ」と説明したところ、ようやく状況が理解できた模様。というか、「Bluetooth」という単語すら知らないのにいきなり思い付きでワイヤレス製品を購入とか…。なんだかな…。
ウチの中にあるデジタル機器で、Bluetoothを持ってる機器と言えば、スマホかノートPCぐらいしかない。親父さんのスマホとワイヤレススピーカーをペアリングして、たしかに音が鳴ることは確認できた。
しかし、親父さんは、「スマホの音が聞けても意味がない」「TVの音が聞きたい」と言い出した。となると、Bluetooth送信機(トランスミッター)を購入しないといけない…。
件のワイヤレススピーカーは、対応コーデックが aptX、aptX Low Latency (aptX LL)、SBC。さて、コレって何だろう…。自分、Bluetooth関連機器なんてほとんど持ってないから、何が何やら。
_【iPhone 15で高音質&低遅延!】Bluetoothイヤホンの「aptX LL」って何?コーデックとは?|radius|ラディウス株式会社 オーディオ・デジタル音響機器・Lightning製品メーカー
_Bluetoothオーディオの品質向上に貢献するQualcomm aptX - 半導体事業 - マクニカ
_【検証】Bluetoothイヤホンはゲームに使える?遅延を測定・比較してみた!【aptXLL】 | いろいろてすと中
上記のページによると、SBCが昔からあるコーデックだけど、人間の耳では聞こえづらい部分をマスキングしてるそうで、音源が mp3だったりした場合は二重にマスキングされることになって音質的によろしくないらしい。aptX はマスキングしていないので音質が良いのだとか。
更に、aptX に対して遅延を少なくしたのが aptX LL らしいので、TVの音を聞くには aptX LL 対応品を買っておけば良い…のかな? それでも数フレームは遅れて聞こえるらしいけど…。
音楽だけ聴く分には、Bluetooth の遅延云々はどうでもいいのだろうけど、TVを見ながら音声を聞く場合は、遅延云々は無視できない。画面の中の人が口をパクパクしてしばらくしてから音声が聞こえてきたら使い物にならない。全ての番組の全ての出演者がプチいっこく堂さんになってしまう。
そんなわけで、aptX LL対応の Bluetoothトランスミッター(送信機)をググってみたのだけど、種類が少ない…。
考えてみれば、当然かもしれない。例えばスマホの場合は Bluetooth機能を最初から持ってるし、今時店頭で販売されてる高機能TV(REGZA等)も Bluetooth機能を持っていたりするようなので、今から新規にその手の機器を購入して使う場合、別途 Bluetoothトランスミッターの購入が必要になることはまずないのだろう。最初からその機器に入っちゃってるから。
つまるところ、Bluetoothなんて持ってない昔のデジタル機器をどうにかしてワイヤレス対応にしたい、という場面でのみ、Bluetoothトランスミッターが必要になるわけだから、そりゃ種類も少なくなるよなと…。製品ジャンル自体がマイナーになってしまったのだろう…。
購入した製品の型番は、audio-technica AT-NSP300BT。
_AT-NSP300BT|AVアクセサリー:スピーカー|オーディオテクニカ
説明書を見たら、予想通り、Bluetooth接続のワイヤレススピーカーだった。ウチの茶の間に置いてあるTVは、TOSHIBA REGZA Z9000 という古い製品なので、Bluetooth送信機能なんてついてるはずもなく。親父さんに、「貴方は送信機を持ってないのに、今回受信機だけを買ってしまったんですよ」と説明したところ、ようやく状況が理解できた模様。というか、「Bluetooth」という単語すら知らないのにいきなり思い付きでワイヤレス製品を購入とか…。なんだかな…。
ウチの中にあるデジタル機器で、Bluetoothを持ってる機器と言えば、スマホかノートPCぐらいしかない。親父さんのスマホとワイヤレススピーカーをペアリングして、たしかに音が鳴ることは確認できた。
しかし、親父さんは、「スマホの音が聞けても意味がない」「TVの音が聞きたい」と言い出した。となると、Bluetooth送信機(トランスミッター)を購入しないといけない…。
件のワイヤレススピーカーは、対応コーデックが aptX、aptX Low Latency (aptX LL)、SBC。さて、コレって何だろう…。自分、Bluetooth関連機器なんてほとんど持ってないから、何が何やら。
_【iPhone 15で高音質&低遅延!】Bluetoothイヤホンの「aptX LL」って何?コーデックとは?|radius|ラディウス株式会社 オーディオ・デジタル音響機器・Lightning製品メーカー
_Bluetoothオーディオの品質向上に貢献するQualcomm aptX - 半導体事業 - マクニカ
_【検証】Bluetoothイヤホンはゲームに使える?遅延を測定・比較してみた!【aptXLL】 | いろいろてすと中
上記のページによると、SBCが昔からあるコーデックだけど、人間の耳では聞こえづらい部分をマスキングしてるそうで、音源が mp3だったりした場合は二重にマスキングされることになって音質的によろしくないらしい。aptX はマスキングしていないので音質が良いのだとか。
更に、aptX に対して遅延を少なくしたのが aptX LL らしいので、TVの音を聞くには aptX LL 対応品を買っておけば良い…のかな? それでも数フレームは遅れて聞こえるらしいけど…。
音楽だけ聴く分には、Bluetooth の遅延云々はどうでもいいのだろうけど、TVを見ながら音声を聞く場合は、遅延云々は無視できない。画面の中の人が口をパクパクしてしばらくしてから音声が聞こえてきたら使い物にならない。全ての番組の全ての出演者がプチいっこく堂さんになってしまう。
そんなわけで、aptX LL対応の Bluetoothトランスミッター(送信機)をググってみたのだけど、種類が少ない…。
考えてみれば、当然かもしれない。例えばスマホの場合は Bluetooth機能を最初から持ってるし、今時店頭で販売されてる高機能TV(REGZA等)も Bluetooth機能を持っていたりするようなので、今から新規にその手の機器を購入して使う場合、別途 Bluetoothトランスミッターの購入が必要になることはまずないのだろう。最初からその機器に入っちゃってるから。
つまるところ、Bluetoothなんて持ってない昔のデジタル機器をどうにかしてワイヤレス対応にしたい、という場面でのみ、Bluetoothトランスミッターが必要になるわけだから、そりゃ種類も少なくなるよなと…。製品ジャンル自体がマイナーになってしまったのだろう…。
[ ツッコむ ]
以上、1 日分です。