string: Độ dài, tìm kiếm và phạm vi

NUL Mô tả đơn vị byte của chuỗi kết thúc API và giá trị trả về.

Wave Foundation

Điều kiện lưu trữ và đối số chuỗi

Đối số str cho mô-đun này phải là byte kết thúc NUL có thể truy cập được. Độ dài và chỉ mục tìm kiếm được tính bằng byte. Các ký tự thông thường được lưu trữ dưới dạng UTF-8, nhưng tìm kiếm theo byte là Unicode mà không cần chuẩn hóa hoặc phân tách từng ký tự. Đừng cho rằng chỉ mục trả về là ranh giới ký tự.

So sánh với chiều dài

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 không bao gồm NUL cuối cùng. cmp Thứ tự được đánh giá bằng dấu của kết quả. Giá trị trả về không được hiểu là thứ tự ký tự Unicode hoặc sắp xếp từ điển theo ngôn ngữ cụ thể. Các chức năng này không phân bổ bộ nhớ và không thay đổi đầu vào của chúng.

tìm kiếm

Lấy tên bạn cần, chẳng hạn như import("std::string::find")::{find, contains, count};.

khai báo hàm kết quả
find(s: str, needle: str) -> i32 Địa điểm trận đấu đầu tiên. -1 nếu không có, 0 nếu trống needle
contains(s: str, needle: str) -> bool Bao gồm hoặc không. Trống needle là true
count(s: str, needle: str) -> i32 Số lượng kết quả trùng khớp không trùng lặp. Thùng needle là 0
find_char(s: str, c: u8) -> i32 vị trí đầu tiên của byte hoặc -1
rfind_char(s: str, c: u8) -> i32 Vị trí cuối cùng của byte hoặc -1
contains_char(s: str, c: u8) -> bool Sự tồn tại của byte đó
count_char(s: str, c: u8) -> i32 số byte được đề cập

c trong tên *_char là một byte, không phải là điểm mã Unicode. Bản thân NUL ở cuối chuỗi không được đưa vào mục tiêu tìm kiếm.

Phạm vi không bao gồm khoảng trắng

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 ghi phạm vi nửa mở [start, end) không bao gồm khoảng trắng ASCII vào đối số đầu ra. Cả hai con trỏ đầu ra phải trỏ đến số nguyên có thể ghi. Nó không sửa đổi văn bản gốc hoặc tạo chuỗi mới. Nếu mọi thứ đều trống, nó sẽ trở thành một phạm vi trống.

Ví dụ đang chạy

Lưu nó vào main.wave và chạy 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"));
}

Kết quả thực hiện:

2 6
2 2

Tính năng liên quan

Việc chuyển đổi phân loại/trường hợp của std::string::ascii dành cho phạm vi ASCII. djb2_32 và fnv1a_64 của std::string::hash không được sử dụng để băm mật mã hoặc lưu trữ mật khẩu. Đối với dữ liệu chứa NUL, hãy sử dụng bytes.

Các mẫu trùng lặp với cụm từ tìm kiếm trống

Xem hành vi biên của hàm tìm kiếm với các giá trị thực tế giúp xác định điều kiện gọi dễ dàng hơn.

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");
    }
}

Kết quả thực hiện:

empty find=0
empty count=0
nonoverlapping=2
empty needle is contained

Giá trị thành công của find, 0, là vị trí đầu tiên. Giá trị thành công bằng 0 cho count là kết quả của quy tắc cụm từ tìm kiếm trống hoặc không khớp. Không có hai giá trị nào được đối xử như nhau. Nếu cần bỏ qua trường hợp hoặc cần chuẩn hóa Unicode thì các chính sách riêng biệt phải được triển khai trước và sau tìm kiếm byte này.

trim Sao chép phạm vi sang chuỗi mới

Không có phần kết thúc mới NUL trong phạm vi được trả về bởi trim_range. Khi sao chép sang một đích riêng biệt, hãy đặt trước độ dài + 1 dấu cách và ghi trực tiếp byte cuối cùng là 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;
}

Kết quả thực hiện:

Wave

Một chuỗi có độ dài 16 sẽ không vừa với đích này. Điều này là do bạn cần NUL cuối cùng. Ngay cả khi độ dài bằng 0, việc viết destination[0]=0 sẽ dẫn đến một chuỗi trống hợp lệ. Mảng cục bộ đích tồn tại cho đến hết main, vì vậy chúng tôi in bên trong mảng đó.

Chuỗi API Thứ tự sử dụng

Khi thiết kế API chuỗi, hãy chỉ định xem đầu vào của nó có được kết thúc bằng NUL hay không, liệu các chỉ mục có đếm byte hay không và liệu kết quả có mượn một phạm vi nguồn hay sở hữu một phân bổ mới hay không. Phạm vi mượn phụ thuộc vào thời gian tồn tại của nguồn. Một kết quả được phân bổ phải chỉ rõ ai giải phóng nó.

Đọc Chương học về chuỗi để biết các khái niệm cơ bản và bytes để biết dữ liệu bao gồm NUL.