summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorBrian Anderson <andersrb@gmail.com>2012-02-11 17:42:45 -0800
committerBrian Anderson <andersrb@gmail.com>2012-02-11 17:42:45 -0800
commit737db5b49a47593529395d2d9225ca2eaa684634 (patch)
treef7c0923b454f2f856d79c9deec181f1fb200e6ba /src/libcore
parentc82a0d7c3c0c0fda158102af7bc5af2823df2f06 (diff)
parent207bb3d2df92f896145b3f2ef8aa5ca5cea00104 (diff)
downloadrust-737db5b49a47593529395d2d9225ca2eaa684634.tar.gz
rust-737db5b49a47593529395d2d9225ca2eaa684634.zip
Merge pull request #1812 from killerswan/indexing2
(core::str) Fixing index and rindex
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/str.rs129
1 files changed, 96 insertions, 33 deletions
diff --git a/src/libcore/str.rs b/src/libcore/str.rs
index b98d96bb901..ca7bb819443 100644
--- a/src/libcore/str.rs
+++ b/src/libcore/str.rs
@@ -253,15 +253,12 @@ Function: pop_char
 Remove the final character from a string and return it.
 
 Failure:
-
 If the string does not contain any characters.
 */
 fn pop_char(&s: str) -> char unsafe {
     let end = byte_len(s);
-    while end > 0u && s[end - 1u] & 192u8 == tag_cont_u8 { end -= 1u; }
-    assert (end > 0u);
-    let ch = char_at(s, end - 1u);
-    s = unsafe::slice_bytes(s, 0u, end - 1u);
+    let {ch:ch, prev:end} = char_range_at_reverse(s, end);
+    s = unsafe::slice_bytes(s, 0u, end);
     ret ch;
 }
 
@@ -868,32 +865,50 @@ fn lines_iter(ss: str, ff: fn(&&str)) {
 Section: Searching
 */
 
-/*
-Function: index
+// Function: index
+//
+// Returns the index of the first matching char
+// (as option some/none)
+fn index(ss: str, cc: char) -> option<uint> {
+    let bii = 0u;
+    let cii = 0u;
+    let len = byte_len(ss);
+    while bii < len {
+        let {ch, next} = char_range_at(ss, bii);
 
-Returns the index of the first matching byte. Returns -1 if
-no match is found.
+        // found here?
+        if ch == cc {
+            ret option::some(cii);
+        }
 
-FIXME: UTF-8
-*/
-fn index(s: str, c: u8) -> int {
-    let i: int = 0;
-    for k: u8 in s { if k == c { ret i; } i += 1; }
-    ret -1;
-}
+        cii += 1u;
+        bii = next;
+    }
 
-/*
-Function: rindex
+    // wasn't found
+    ret option::none;
+}
 
-Returns the index of the last matching byte. Returns -1
-if no match is found.
+// Function: rindex
+//
+// Returns the index of the first matching char
+// (as option some/none)
+fn rindex(ss: str, cc: char) -> option<uint> {
+    let bii = byte_len(ss);
+    let cii = char_len(ss);
+    while bii > 0u {
+        let {ch, prev} = char_range_at_reverse(ss, bii);
+        cii -= 1u;
+        bii = prev;
+
+        // found here?
+        if ch == cc {
+            ret option::some(cii);
+        }
+    }
 
-FIXME: UTF-8
-*/
-fn rindex(s: str, c: u8) -> int {
-    let n: int = byte_len(s) as int;
-    while n >= 0 { if s[n] == c { ret n; } n -= 1; }
-    ret n;
+    // wasn't found
+    ret option::none;
 }
 
 /*
@@ -1233,6 +1248,25 @@ Pluck a character out of a string
 */
 fn char_at(s: str, i: uint) -> char { ret char_range_at(s, i).ch; }
 
+// Function: char_range_at_reverse
+//
+// Given a byte position and a str, return the previous char and its position
+// This function can be used to iterate over a unicode string in reverse.
+fn char_range_at_reverse(ss: str, start: uint) -> {ch: char, prev: uint} {
+    let prev = start;
+
+    // while there is a previous byte == 10......
+    while prev > 0u && ss[prev - 1u] & 192u8 == tag_cont_u8 {
+        prev -= 1u;
+    }
+
+    // now refer to the initial byte of previous char
+    prev -= 1u;
+
+    let ch = char_at(ss, prev);
+    ret {ch:ch, prev:prev};
+}
+
 /*
 Function: substr_all
 
@@ -1442,13 +1476,42 @@ mod tests {
     }
 
     #[test]
-    fn test_index_and_rindex() {
-        assert (index("hello", 'e' as u8) == 1);
-        assert (index("hello", 'o' as u8) == 4);
-        assert (index("hello", 'z' as u8) == -1);
-        assert (rindex("hello", 'l' as u8) == 3);
-        assert (rindex("hello", 'h' as u8) == 0);
-        assert (rindex("hello", 'z' as u8) == -1);
+    fn test_index() {
+        assert ( index("hello", 'h') == option::some(0u));
+        assert ( index("hello", 'e') == option::some(1u));
+        assert ( index("hello", 'o') == option::some(4u));
+        assert ( index("hello", 'z') == option::none);
+    }
+
+    #[test]
+    fn test_rindex() {
+        assert (rindex("hello", 'l') == option::some(3u));
+        assert (rindex("hello", 'o') == option::some(4u));
+        assert (rindex("hello", 'h') == option::some(0u));
+        assert (rindex("hello", 'z') == option::none);
+    }
+
+    #[test]
+    fn test_pop_char() {
+        let data = "ประเทศไทย中华";
+        let cc = pop_char(data);
+        assert "ประเทศไทย中" == data;
+        assert '华' == cc;
+    }
+
+    #[test]
+    fn test_pop_char_2() {
+        let data2 = "华";
+        let cc2 = pop_char(data2);
+        assert "" == data2;
+        assert '华' == cc2;
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_pop_char_fail() {
+        let data = "";
+        let _cc3 = pop_char(data);
     }
 
     #[test]