string: 長さ、検索、範囲
NUL終了文字列のバイト単位APIと戻り値を説明します。
Wave Foundation
文字列の格納と引数条件
このモジュールのstr引数は、アクセス可能なNUL終了バイト列でなければなりません。長さと検索インデックスはバイト単位です。一般文字はUTF-8として保存されますが、バイト検索はUnicode正規化や文字単位の分割は行いません。返されたインデックスが文字境界であると仮定しないでください。
長さと比較
std::string::len
len(s: str) -> i32
is_empty(s: str) -> bool
std::string::cmp
eq(a: str, b: str) -> bool
cmp(a: str, b: str) -> i32
starts_with(s: str, prefix: str) -> bool
ends_with(s: str, suffix: str) -> bool
lenは最後のNULを除外します。 cmp結果の符号で順序を判断します。戻り値を Unicode 文字順や言語別の事前ソートとして解釈しません。これらの関数はメモリを割り当てずに入力を変更しません。
検索
import("std::string::find")::{find, contains, count};のように必要な名前を取得します。
| 関数宣言 | 結果 |
|---|---|
find(s: str, needle: str) -> i32 |
最初の一致位置。なければ-1、空のneedleは0 |
contains(s: str, needle: str) -> bool |
含めるかどうか。空 needleはtrue |
count(s: str, needle: str) -> i32 |
重複しない一致数。空needleは0 |
find_char(s: str, c: u8) -> i32 |
バイトの最初の位置または-1 |
rfind_char(s: str, c: u8) -> i32 |
バイトの最後の位置または-1 |
contains_char(s: str, c: u8) -> bool |
そのバイトの存在 |
count_char(s: str, c: u8) -> i32 |
対応するバイト数 |
*_charという名前のcは、Unicodeコードポイントではなく1バイトです。文字列の末尾のNUL自体は検索対象には含まれません。
スペースを除く範囲
std::string::trim
trim_left_index(s: str) -> i32
trim_right_index(s: str) -> i32
trim_range(s: str, out_start: ptr<i32>, out_end: ptr<i32>)
trim_rangeは、ASCII空白を除いた半開範囲[start, end)を出力係数に記録します。両方の出力ポインタは書き込み可能な整数を指す必要があります。原文を変更したり、新しい文字列を作成したりしません。すべて空白の場合は空の範囲になります。
実行例
main.waveに保存し、wavec run main.waveを実行します。
import("std::string::find")::{
find, count
};
import("std::string::trim")::{
trim_range
};
fun main() {
var start: i32 = 0;
var end: i32 = 0;
trim_range(" Wave ", &start, &end);
println("{} {}", start, end);
println("{} {}", find("banana", "na"), count("aaaa", "aa"));
}
実行結果:
2 6
2 2
関連機能
std::string::asciiの分類・大小文字変換はASCII範囲用です。 std::string::hashのdjb2_32とfnv1a_64を暗号ハッシュやパスワード保存には使用しません。 NULを含むデータにはbytesを使用してください。
空のクエリと重なるパターン
検索関数のエッジの振る舞いを実際の値として調べると、呼び出し条件を決めるのは簡単です。
import("std::string::find")::{find, contains, count};
fun main() {
println("empty find={}", find("Wave", ""));
println("empty count={}", count("Wave", ""));
println("nonoverlapping={}", count("aaaa", "aa"));
if (contains("Wave", "")) {
println("empty needle is contained");
}
}
実行結果:
empty find=0
empty count=0
nonoverlapping=2
empty needle is contained
findの成功値0は最初の位置です。 countの成功値0は一致しないか、空のクエリルールの結果です。両方の値を同じ条件で処理しません。大文字と小文字を無視するか、Unicode正規化が必要な場合は、このバイト検索の前後に別々のポリシーを実装する必要があります。
trim 範囲を新しい文字列にコピーする
trim_rangeが返す範囲には終了NULが新しくなりません。別の宛先にコピーする場合は、長さ+1のスペースを確保し、最後のバイトを直接0に書き込みます。
import("std::string::trim")::{trim_range};
fun main() -> i32 {
var original: str = " Wave ";
var start: i32 = 0;
var end: i32 = 0;
var destination: array<u8, 16>;
trim_range(original, &start, &end);
var length: i32 = end - start;
if (length >= 16) {
return 1;
}
for (var index: i32 = 0; index < length; index += 1) {
destination[index] = original[start + index];
}
destination[length] = 0;
println("{}", &destination[0] as str);
return 0;
}
実行結果:
Wave
長さ16の文字列はこの宛先には入りません。最後のNULまで必要だからです。長さが 0 であっても destination[0]=0 を記録すると有効な空文字列になります。目的地エリア配列はmainの終わりまで生きているので、その中から出力します。
文字列API使用順序
文字列 API を設計するときは、入力が NUL で終了するかどうか、インデックスがバイト数をカウントするかどうか、結果がソース範囲を借用するか新しい割り当てを所有するかを指定します。借用範囲はソースの存続期間によって異なります。割り当てられた結果では、誰がそれを解放するかを指定する必要があります。