/* Copyright 2019-2022 René Ferdinand Rivera Morell Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.txt or https://www.bfgroup.xyz/b2/LICENSE.txt) */ #include "mod_string.h" #include static const char * whitespace_chars = " \t\n"; b2::value_ref b2::string_whitespace() { return b2::value_ref(b2::value::make(whitespace_chars)); } b2::list_ref b2::string_chars(b2::value_ref string) { list_ref chars; for (auto ch : string->as_string()) chars.push_back(value::make(&ch, 1)); return chars; } b2::value_ref b2::string_abbreviate(b2::value_ref string) { // Anything less than 4 characters gets no abbreviation. if (string->as_string().size < 4) return string; std::string s = string->str(); // Separate the initial letter in case it's a vowel. auto first_c = s[0]; s.erase(0, 1); // Drop trailing "ing". if (s.compare(s.size() - 3, 3, "ing") == 0) s.erase(s.size() - 3); // Reduce all doubled characters to one. s.erase(std::unique(s.begin(), s.end()), s.end()); // Chop all vowels out of the remainder. s.erase(std::remove_if(s.begin(), s.end(), [](std::string::value_type c) { // Sorted by English vowel frequency. return c == 'e' || c == 'E' || c == 'a' || c == 'A' || c == 'o' || c == 'O' || c == 'i' || c == 'I' || c == 'u' || c == 'U'; }), s.end()); // Shorten remaining consonants to 4 characters. if (s.size() > 4) s.erase(4); // Glue the initial character back on to the front. s.insert(0, 1, first_c); return value_ref(value::make(s.c_str())); } b2::value_ref b2::string_join(b2::list_cref strings, b2::value_ref separator) { if (strings.empty()) return value_ref(value::make("")); std::string result = (*strings.begin())->str(); auto strings_i = ++strings.begin(); auto strings_e = strings.end(); for (; strings_i != strings_e; ++strings_i) { if (separator.has_value()) result += separator->str(); result += (*strings_i)->str(); } return value_ref(value::make(result.c_str())); } b2::list_ref b2::string_words(std::string s, b2::list_cref whitespace) { std::string delimiters { whitespace_chars }; if (!whitespace.empty()) delimiters = string_join(whitespace, value_ref(value::make(""))); list_ref words; std::string::size_type word_begin = 0; std::string::size_type word_ws = s.find_first_of(delimiters); while (word_ws != std::string::npos) { words.push_back(s.substr(word_begin, word_ws - word_begin)); word_begin = s.find_first_not_of(delimiters, word_ws + 1); word_ws = s.find_first_of(delimiters, word_begin); } if (word_begin < s.size()) words.push_back(s.substr(word_begin)); return words; } bool b2::string_is_whitespace(value_ref s) { if (!s.has_value()) return true; if (s->get_type() != value::type::string) return false; for (auto c : s->as_string()) { if (c != ' ' && c != '\t' && c != '\n') return false; } return true; } const char * b2::string_module::init_code = R"jam( rule __test__ ( ) { import assert ; assert.result a b c : chars abc ; assert.result rntm : abbreviate runtime ; assert.result ovrld : abbreviate overload ; assert.result dbg : abbreviate debugging ; assert.result async : abbreviate asynchronous ; assert.result pop : abbreviate pop ; assert.result aaa : abbreviate aaa ; assert.result qck : abbreviate quack ; assert.result sttc : abbreviate static ; # Check boundary cases. assert.result a : chars a ; assert.result : chars "" ; assert.result a b c d e f g h : chars abcdefgh ; assert.result a b c d e f g h i : chars abcdefghi ; assert.result a b c d e f g h i j : chars abcdefghij ; assert.result a b c d e f g h i j k : chars abcdefghijk ; assert.result a//b/c/d : join a "" b c d : / ; assert.result abcd : join a "" b c d ; assert.result a b c : words "a b c" ; assert.true is-whitespace " " ; assert.false is-whitespace " a b c " ; assert.true is-whitespace "" ; assert.true is-whitespace ; } )jam";