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つ追加すれば」などと書いてしまったけれど。考えてみたらマルチバイト文字列への対応が面倒なのではと思えてきた…。
[ ツッコむ ]
以上です。