ascii

模块说明

ascii模块定义了MoveASCII编码字符串(String)和字符(Char)类型。并提供了一系列的操作方法,用于字符串与字节数组、字符与u8之间的相互转换;以及字符串的常用操作,包括:追加、截取、计算长度、判断是否为空、判断是否合法等等。

源码路径

https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/packages/move-stdlib/sources/ascii.move

方法图解

方法说明

分类方法说明
类型转换方法as_bytes()ASCII编码字符串引用转字节数组引用
into_bytes()ASCII编码字符串转字节数组
string()字节数组转ASCII编码字符串
try_string()字节数组转Option ASCII编码字符串
to_string()ASCII编码字符串转UTF-8编码字符串
byte()字符转u8数字
char()u8数字转字符
字符串方法length()计算字符串长度
substring()从字符串中取子串
is_empty()判断字符串是否为空
index_of()获取子串首次出现位置
to_uppercase()字符串转大些
to_lowercase()字符串转小写
all_characters_printable()判断字符串是否均为可打印字符
insert()在字符串指定位置插入字符串
append()在字符串最后插入字符串
pop_char()从字符串尾部弹出字符
字符方法is_valid_char判断是否有有效字符
is_printable_char判断是否是可打印字符

代码示例

module cookbook::ascii_demo {
    use std::ascii::{Self, String, Char};

    const EInvalidBookIdx: u64 = 1;

    public struct Bookshelf has key {
		id: UID,
		books: vector<Book>,
        book_count: u64
	}

    public struct Book has store {
		idx: u64,
		title: String, 
        category: Char,
	}

    public fun create_bookshelf(ctx: &mut TxContext) {
        transfer::share_object(Bookshelf {
            id: object::new(ctx),
            books: vector::empty(),
            book_count: 0,
        });
	}

    public fun add_book(
        bookshelf: &mut Bookshelf,
        title: vector<u8>,
        category: u8
    ) {

        let book_id = bookshelf.books.length();

        let book = Book {
            idx: book_id,
            title: ascii::string(title),
            category: ascii::char(category),
        };

        bookshelf.books.push_back(book);
        bookshelf.book_count = bookshelf.book_count + 1;
    }

    public fun get_books(bookshelf: &Bookshelf):  &vector<Book> {
        &bookshelf.books
    }

    public fun get_book(bookshelf: &Bookshelf, idx: u64):  &Book {
        assert!(bookshelf.books.length() > idx, EInvalidBookIdx);
        &bookshelf.books[idx]
    }

    public fun get_book_mut_ref(bookshelf: &mut Bookshelf, idx: u64):  &mut Book {
        assert!(bookshelf.books.length() > idx, EInvalidBookIdx);
        &mut bookshelf.books[idx]
    }

    public fun get_title(book: &Book): String {
        book.title
    }

    public fun get_title_ref(book: &Book): &String {
        &book.title
    }

    public fun get_title_mut_ref(book: &mut Book): &mut String {
        &mut book.title
    }

    public fun get_category(book: &Book): Char {
        book.category
    }
}

#[test_only]
module cookbook::ascii_demo_test {
    use std::ascii;
    use std::string;
    use sui::test_scenario as ts;
    use cookbook::ascii_demo::{Bookshelf, create_bookshelf, add_book, get_books};

    #[test_only]
    use sui::test_utils::assert_eq;

    #[test]
    public fun test_ascii() {
        let alice = @0xa;    

        let mut ts = ts::begin(alice);

        {
            create_bookshelf(ts.ctx());
        };

        let expected_title = b"Mastering Bitcoin";
        let expected_category = 0x41;
        {
            ts.next_tx(alice);
            let mut bookshelf: Bookshelf = ts.take_shared();

            add_book(
                &mut bookshelf, 
                expected_title, 
                expected_category
            );

            ts::return_shared(bookshelf);
        };

        {
            ts.next_tx(alice);
            let bookshelf: Bookshelf = ts.take_shared();
            let books = bookshelf.get_books();
            assert_eq(books.length(), 1);

            {
                let book = bookshelf.get_book(0);
                let title = book.get_title();
                assert_eq(title.into_bytes(), expected_title);
                assert_eq(title, ascii::string(expected_title));
                assert_eq(option::some(title), ascii::try_string(expected_title));
                assert_eq(title.to_string(), string::utf8(expected_title));
            };

            {
                let book = bookshelf.get_book(0);
                let title_ref = book.get_title_ref();
                assert_eq(title_ref.length(), expected_title.length());
                assert_eq(title_ref.substring(10, 17), b"Bitcoin".to_ascii_string());
                assert_eq(title_ref.is_empty(), false);
                assert_eq(title_ref.index_of(&b"Bitcoin".to_ascii_string()), 10);
                assert_eq(title_ref.to_uppercase(), b"MASTERING BITCOIN".to_ascii_string());
                assert_eq(title_ref.to_lowercase(), b"mastering bitcoin".to_ascii_string());
                assert_eq(title_ref.all_characters_printable(), true);
                assert_eq(*title_ref.as_bytes(), expected_title);  // OK
                assert!(title_ref.as_bytes() == &expected_title);  // OK
                // assert_eq(title_ref.as_bytes(), &expected_title);  // ERROR assert_eq不支持引用
            };

            ts::return_shared(bookshelf);
        };

        {
            ts.next_tx(alice);
            let mut bookshelf: Bookshelf = ts.take_shared();
            let book = bookshelf.get_book_mut_ref(0);
            let title_mut_ref = book.get_title_mut_ref();

            {
                title_mut_ref.insert(17, b" and ".to_ascii_string());
                assert!(title_mut_ref == b"Mastering Bitcoin and ".to_ascii_string());

                title_mut_ref.append(b"Move".to_ascii_string());
                assert!(title_mut_ref == b"Mastering Bitcoin and Move".to_ascii_string());

                assert_eq(title_mut_ref.pop_char(), ascii::char(0x65)); // e
                assert_eq(title_mut_ref.pop_char(), ascii::char(0x76)); // v
                assert_eq(title_mut_ref.pop_char(), ascii::char(0x6F)); // o
                assert_eq(title_mut_ref.pop_char(), ascii::char(0x4D)); // M

                assert!(title_mut_ref == b"Mastering Bitcoin and ".to_ascii_string());
            };

            ts::return_shared(bookshelf);
        };

        {
            ts.next_tx(alice);
            let bookshelf: Bookshelf = ts.take_shared();
            {
                let book = bookshelf.get_book(0);
                let category = book.get_category();
                assert_eq(category.byte(), 0x41);
                assert_eq(category, ascii::char(0x41));

                assert_eq(ascii::is_valid_char(0x41), true);
                assert_eq(ascii::is_printable_char(0x41), true);
                assert_eq(ascii::is_printable_char(0x7F), false);
            };

            ts::return_shared(bookshelf);
        };

        ts.end();
    }
}