X-Git-Url: http://nitlanguage.org diff --git a/lib/standard/string.nit b/lib/standard/string.nit index 409b4ed..ff46e46 100644 --- a/lib/standard/string.nit +++ b/lib/standard/string.nit @@ -60,7 +60,7 @@ abstract class Text fun substring(from: Int, count: Int): SELFTYPE is abstract # Iterates on the substrings of self if any - fun substrings: Iterator[Text] is abstract + fun substrings: Iterator[FlatText] is abstract # Is the current Text empty (== "") # @@ -249,6 +249,16 @@ abstract class Text # assert "ff".to_hex == 255 fun to_hex: Int do return a_to(16) + # If `self` contains only digits <= '7', return the corresponding integer. + # + # assert "714".to_oct == 460 + fun to_oct: Int do return a_to(8) + + # If `self` contains only '0' et '1', return the corresponding integer. + # + # assert "101101".to_bin == 45 + fun to_bin: Int do return a_to(2) + # If `self` contains only digits and letters, return the corresponding integer in a given base # # assert "120".a_to(3) == 15 @@ -345,7 +355,7 @@ abstract class Text end return true end - + # Removes the whitespaces at the beginning of self # # assert " \n\thello \n\t".l_trim == "hello \n\t" @@ -849,6 +859,60 @@ abstract class Text return hash_cache.as(not null) end + # Gives the formatted string back as a Nit string with `args` in place + # + # assert "This %1 is a %2.".format("String", "formatted String") == "This String is a formatted String." + # assert "\\%1 This string".format("String") == "\\%1 This string" + fun format(args: Object...): String do + var s = new Array[Text] + var curr_st = 0 + var i = 0 + while i < length do + # Skip escaped characters + if self[i] == '\\' then + i += 1 + # In case of format + else if self[i] == '%' then + var fmt_st = i + i += 1 + var ciph_st = i + while i < length and self[i].is_numeric do + i += 1 + end + i -= 1 + var fmt_end = i + var ciph_len = fmt_end - ciph_st + 1 + s.push substring(curr_st, fmt_st - curr_st) + s.push args[substring(ciph_st, ciph_len).to_i - 1].to_s + curr_st = i + 1 + end + i += 1 + end + s.push substring(curr_st, length - curr_st) + return s.to_s + end + + # Copies `n` bytes from `self` at `src_offset` into `dest` starting at `dest_offset` + # + # Basically a high-level synonym of NativeString::copy_to + # + # REQUIRE: `n` must be large enough to contain `len` bytes + # + # var ns = new NativeString(8) + # "Text is String".copy_to_native(ns, 8, 2, 0) + # assert ns.to_s_with_length(8) == "xt is St" + # + fun copy_to_native(dest: NativeString, n, src_offset, dest_offset: Int) do + var mypos = src_offset + var itspos = dest_offset + while n > 0 do + dest[itspos] = self.chars[mypos] + itspos += 1 + mypos += 1 + n -= 1 + end + end + end # All kinds of array-based text representations. @@ -881,7 +945,7 @@ abstract class FlatText # copy locally the char* as Nit Strings are immutable. private fun fast_cstring: NativeString is abstract - redef var length: Int = 0 + redef var length = 0 redef fun output do @@ -893,6 +957,10 @@ abstract class FlatText end redef fun flatten do return self + + redef fun copy_to_native(dest, n, src_offset, dest_offset) do + items.copy_to(dest, n, src_offset, dest_offset) + end end # Abstract class for the SequenceRead compatible @@ -953,7 +1021,7 @@ abstract class String # assert "helloworld".insert_at(" ", 5) == "hello world" fun insert_at(s: String, pos: Int): SELFTYPE is abstract - redef fun substrings: Iterator[String] is abstract + redef fun substrings is abstract # Returns a reversed version of self # @@ -972,41 +1040,61 @@ abstract class String # assert "Hello World!".to_lower == "hello world!" fun to_lower : SELFTYPE is abstract - # Takes a camel case `self` and converts it to snake case + # Takes a camel case `self` and converts it to snake case # # assert "randomMethodId".to_snake_case == "random_method_id" # - # If `self` is upper, it is returned unchanged + # The rules are the following: # - # assert "RANDOM_METHOD_ID".to_snake_case == "RANDOM_METHOD_ID" + # An uppercase is always converted to a lowercase # - # If the identifier is prefixed by an underscore, the underscore is ignored + # assert "HELLO_WORLD".to_snake_case == "hello_world" + # + # An uppercase that follows a lowercase is prefixed with an underscore # - # assert "_privateField".to_snake_case == "_private_field" + # assert "HelloTheWORLD".to_snake_case == "hello_the_world" + # + # An uppercase that follows an uppercase and is followed by a lowercase, is prefixed with an underscore + # + # assert "HelloTHEWorld".to_snake_case == "hello_the_world" + # + # All other characters are kept as is; `self` does not need to be a proper CamelCased string. + # + # assert "=-_H3ll0Th3W0rld_-=".to_snake_case == "=-_h3ll0th3w0rld_-=" fun to_snake_case: SELFTYPE do - if self.is_upper then return self + if self.is_lower then return self var new_str = new FlatBuffer.with_capacity(self.length) - var is_first_char = true + var prev_is_lower = false + var prev_is_upper = false for i in [0..length[ do var char = chars[i] - if is_first_char then - new_str.add(char.to_lower) - is_first_char = false + if char.is_lower then + new_str.add(char) + prev_is_lower = true + prev_is_upper = false else if char.is_upper then - new_str.add('_') + if prev_is_lower then + new_str.add('_') + else if prev_is_upper and i+1 < length and chars[i+1].is_lower then + new_str.add('_') + end new_str.add(char.to_lower) + prev_is_lower = false + prev_is_upper = true else new_str.add(char) + prev_is_lower = false + prev_is_upper = false end end - + return new_str.to_s end - # Takes a snake case `self` and converts it to camel case + # Takes a snake case `self` and converts it to camel case # # assert "random_method_id".to_camel_case == "randomMethodId" # @@ -1106,7 +1194,7 @@ class FlatString # Indes in _items of the last item of the string private var index_to: Int is noinit - redef var chars: SequenceRead[Char] = new FlatStringCharView(self) is lazy + redef var chars = new FlatStringCharView(self) is lazy redef fun [](index) do @@ -1231,8 +1319,7 @@ class FlatString index_to = to end - redef fun to_cstring: NativeString - do + redef fun to_cstring do if real_items != null then return real_items.as(not null) else @@ -1650,8 +1737,7 @@ class FlatBuffer capacity = c end - redef fun to_s: String - do + redef fun to_s do written = true if length == 0 then items = new NativeString(1) return new FlatString.with_infos(items, length, 0, length - 1) @@ -1952,9 +2038,7 @@ end redef class Int # Wrapper of strerror C function - private fun strerror_ext: NativeString is extern `{ - return strerror(recv); - `} + private fun strerror_ext: NativeString is extern "strerror" # Returns a string describing error number fun strerror: String do return strerror_ext.to_s @@ -2144,6 +2228,12 @@ redef class Collection[E] # Concatenate elements. redef fun to_s do + return plain_to_s + end + + # Concatenate element without separators + fun plain_to_s: String + do var s = new FlatBuffer for e in self do if e != null then s.append(e.to_s) return s.to_s @@ -2179,7 +2269,7 @@ end redef class Array[E] # Fast implementation - redef fun to_s + redef fun plain_to_s do var l = length if l == 0 then return ""