]> git.lizzy.rs Git - rust.git/blob - src/libcore/char.rs
28e0247f00a2557ef1a6e28435b70d246db031aa
[rust.git] / src / libcore / char.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Character manipulation.
12 //!
13 //! For more details, see ::unicode::char (a.k.a. std::char)
14
15 #![allow(non_snake_case)]
16 #![doc(primitive = "char")]
17
18 use iter::Iterator;
19 use mem::transmute;
20 use option::Option::{None, Some};
21 use option::Option;
22 use slice::SliceExt;
23
24 // UTF-8 ranges and tags for encoding characters
25 static TAG_CONT: u8    = 0b1000_0000u8;
26 static TAG_TWO_B: u8   = 0b1100_0000u8;
27 static TAG_THREE_B: u8 = 0b1110_0000u8;
28 static TAG_FOUR_B: u8  = 0b1111_0000u8;
29 static MAX_ONE_B: u32   =     0x80u32;
30 static MAX_TWO_B: u32   =    0x800u32;
31 static MAX_THREE_B: u32 =  0x10000u32;
32
33 /*
34     Lu  Uppercase_Letter        an uppercase letter
35     Ll  Lowercase_Letter        a lowercase letter
36     Lt  Titlecase_Letter        a digraphic character, with first part uppercase
37     Lm  Modifier_Letter         a modifier letter
38     Lo  Other_Letter            other letters, including syllables and ideographs
39     Mn  Nonspacing_Mark         a nonspacing combining mark (zero advance width)
40     Mc  Spacing_Mark            a spacing combining mark (positive advance width)
41     Me  Enclosing_Mark          an enclosing combining mark
42     Nd  Decimal_Number          a decimal digit
43     Nl  Letter_Number           a letterlike numeric character
44     No  Other_Number            a numeric character of other type
45     Pc  Connector_Punctuation   a connecting punctuation mark, like a tie
46     Pd  Dash_Punctuation        a dash or hyphen punctuation mark
47     Ps  Open_Punctuation        an opening punctuation mark (of a pair)
48     Pe  Close_Punctuation       a closing punctuation mark (of a pair)
49     Pi  Initial_Punctuation     an initial quotation mark
50     Pf  Final_Punctuation       a final quotation mark
51     Po  Other_Punctuation       a punctuation mark of other type
52     Sm  Math_Symbol             a symbol of primarily mathematical use
53     Sc  Currency_Symbol         a currency sign
54     Sk  Modifier_Symbol         a non-letterlike modifier symbol
55     So  Other_Symbol            a symbol of other type
56     Zs  Space_Separator         a space character (of various non-zero widths)
57     Zl  Line_Separator          U+2028 LINE SEPARATOR only
58     Zp  Paragraph_Separator     U+2029 PARAGRAPH SEPARATOR only
59     Cc  Control                 a C0 or C1 control code
60     Cf  Format                  a format control character
61     Cs  Surrogate               a surrogate code point
62     Co  Private_Use             a private-use character
63     Cn  Unassigned              a reserved unassigned code point or a noncharacter
64 */
65
66 /// The highest valid code point
67 #[stable(feature = "rust1", since = "1.0.0")]
68 pub const MAX: char = '\u{10ffff}';
69
70 /// Converts a `u32` to an `Option<char>`.
71 ///
72 /// # Examples
73 ///
74 /// ```
75 /// use std::char;
76 ///
77 /// let c = char::from_u32(10084); // produces `Some(❤)`
78 /// assert_eq!(c, Some('❤'));
79 /// ```
80 ///
81 /// An invalid character:
82 ///
83 /// ```
84 /// use std::char;
85 ///
86 /// let none = char::from_u32(1114112);
87 /// assert_eq!(none, None);
88 /// ```
89 #[inline]
90 #[stable(feature = "rust1", since = "1.0.0")]
91 pub fn from_u32(i: u32) -> Option<char> {
92     // catch out-of-bounds and surrogates
93     if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) {
94         None
95     } else {
96         Some(unsafe { transmute(i) })
97     }
98 }
99
100 /// Converts a number to the character representing it.
101 ///
102 /// # Return value
103 ///
104 /// Returns `Some(char)` if `num` represents one digit under `radix`,
105 /// using one character of `0-9` or `a-z`, or `None` if it doesn't.
106 ///
107 /// # Panics
108 ///
109 /// Panics if given an `radix` > 36.
110 ///
111 /// # Examples
112 ///
113 /// ```
114 /// use std::char;
115 ///
116 /// let c = char::from_digit(4, 10);
117 ///
118 /// assert_eq!(c, Some('4'));
119 /// ```
120 #[inline]
121 #[unstable(feature = "core", reason = "pending integer conventions")]
122 pub fn from_digit(num: uint, radix: uint) -> Option<char> {
123     if radix > 36 {
124         panic!("from_digit: radix is too high (maximum 36)");
125     }
126     if num < radix {
127         unsafe {
128             if num < 10 {
129                 Some(transmute(('0' as uint + num) as u32))
130             } else {
131                 Some(transmute(('a' as uint + num - 10) as u32))
132             }
133         }
134     } else {
135         None
136     }
137 }
138
139 /// Basic `char` manipulations.
140 #[stable(feature = "rust1", since = "1.0.0")]
141 pub trait CharExt {
142     /// Checks if a `char` parses as a numeric digit in the given radix.
143     ///
144     /// Compared to `is_numeric()`, this function only recognizes the characters
145     /// `0-9`, `a-z` and `A-Z`.
146     ///
147     /// # Return value
148     ///
149     /// Returns `true` if `c` is a valid digit under `radix`, and `false`
150     /// otherwise.
151     ///
152     /// # Panics
153     ///
154     /// Panics if given a radix > 36.
155     ///
156     /// # Examples
157     ///
158     /// ```
159     /// let c = '1';
160     ///
161     /// assert!(c.is_digit(10));
162     ///
163     /// assert!('f'.is_digit(16));
164     /// ```
165     #[unstable(feature = "core",
166                reason = "pending integer conventions")]
167     fn is_digit(self, radix: uint) -> bool;
168
169     /// Converts a character to the corresponding digit.
170     ///
171     /// # Return value
172     ///
173     /// If `c` is between '0' and '9', the corresponding value between 0 and
174     /// 9. If `c` is 'a' or 'A', 10. If `c` is 'b' or 'B', 11, etc. Returns
175     /// none if the character does not refer to a digit in the given radix.
176     ///
177     /// # Panics
178     ///
179     /// Panics if given a radix outside the range [0..36].
180     ///
181     /// # Examples
182     ///
183     /// ```
184     /// let c = '1';
185     ///
186     /// assert_eq!(c.to_digit(10), Some(1));
187     ///
188     /// assert_eq!('f'.to_digit(16), Some(15));
189     /// ```
190     #[unstable(feature = "core",
191                reason = "pending integer conventions")]
192     fn to_digit(self, radix: uint) -> Option<uint>;
193
194     /// Returns an iterator that yields the hexadecimal Unicode escape of a character, as `char`s.
195     ///
196     /// All characters are escaped with Rust syntax of the form `\\u{NNNN}` where `NNNN` is the
197     /// shortest hexadecimal representation of the code point.
198     ///
199     /// # Examples
200     ///
201     /// ```
202     /// for i in '❤'.escape_unicode() {
203     ///     println!("{}", i);
204     /// }
205     /// ```
206     ///
207     /// This prints:
208     ///
209     /// ```text
210     /// \
211     /// u
212     /// {
213     /// 2
214     /// 7
215     /// 6
216     /// 4
217     /// }
218     /// ```
219     ///
220     /// Collecting into a `String`:
221     ///
222     /// ```
223     /// let heart: String = '❤'.escape_unicode().collect();
224     ///
225     /// assert_eq!(heart, r"\u{2764}");
226     /// ```
227     #[stable(feature = "rust1", since = "1.0.0")]
228     fn escape_unicode(self) -> EscapeUnicode;
229
230     /// Returns an iterator that yields the 'default' ASCII and
231     /// C++11-like literal escape of a character, as `char`s.
232     ///
233     /// The default is chosen with a bias toward producing literals that are
234     /// legal in a variety of languages, including C++11 and similar C-family
235     /// languages. The exact rules are:
236     ///
237     /// * Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively.
238     /// * Single-quote, double-quote and backslash chars are backslash-
239     ///   escaped.
240     /// * Any other chars in the range [0x20,0x7e] are not escaped.
241     /// * Any other chars are given hex Unicode escapes; see `escape_unicode`.
242     ///
243     /// # Examples
244     ///
245     /// ```
246     /// for i in '"'.escape_default() {
247     ///     println!("{}", i);
248     /// }
249     /// ```
250     ///
251     /// This prints:
252     ///
253     /// ```text
254     /// \
255     /// "
256     /// ```
257     ///
258     /// Collecting into a `String`:
259     ///
260     /// ```
261     /// let quote: String = '"'.escape_default().collect();
262     ///
263     /// assert_eq!(quote, "\\\"");
264     /// ```
265     #[stable(feature = "rust1", since = "1.0.0")]
266     fn escape_default(self) -> EscapeDefault;
267
268     /// Returns the number of bytes this character would need if encoded in UTF-8.
269     ///
270     /// # Examples
271     ///
272     /// ```
273     /// let n = 'ß'.len_utf8();
274     ///
275     /// assert_eq!(n, 2);
276     /// ```
277     #[stable(feature = "rust1", since = "1.0.0")]
278     fn len_utf8(self) -> uint;
279
280     /// Returns the number of bytes this character would need if encoded in UTF-16.
281     ///
282     /// # Examples
283     ///
284     /// ```
285     /// let n = 'ß'.len_utf16();
286     ///
287     /// assert_eq!(n, 1);
288     /// ```
289     #[stable(feature = "rust1", since = "1.0.0")]
290     fn len_utf16(self) -> uint;
291
292     /// Encodes this character as UTF-8 into the provided byte buffer, and then returns the number
293     /// of bytes written.
294     ///
295     /// If the buffer is not large enough, nothing will be written into it and a `None` will be
296     /// returned.
297     ///
298     /// # Examples
299     ///
300     /// In both of these examples, 'ß' takes two bytes to encode.
301     ///
302     /// ```
303     /// let mut b = [0; 2];
304     ///
305     /// let result = 'ß'.encode_utf8(&mut b);
306     ///
307     /// assert_eq!(result, Some(2));
308     /// ```
309     ///
310     /// A buffer that's too small:
311     ///
312     /// ```
313     /// let mut b = [0; 1];
314     ///
315     /// let result = 'ß'.encode_utf8(&mut b);
316     ///
317     /// assert_eq!(result, None);
318     /// ```
319     #[stable(feature = "rust1", since = "1.0.0")]
320     fn encode_utf8(self, dst: &mut [u8]) -> Option<uint>;
321
322     /// Encodes this character as UTF-16 into the provided `u16` buffer, and then returns the
323     /// number of `u16`s written.
324     ///
325     /// If the buffer is not large enough, nothing will be written into it and a `None` will be
326     /// returned.
327     ///
328     /// # Examples
329     ///
330     /// In both of these examples, 'ß' takes one byte to encode.
331     ///
332     /// ```
333     /// let mut b = [0; 1];
334     ///
335     /// let result = 'ß'.encode_utf16(&mut b);
336     ///
337     /// assert_eq!(result, Some(1));
338     /// ```
339     ///
340     /// A buffer that's too small:
341     ///
342     /// ```
343     /// let mut b = [0; 0];
344     ///
345     /// let result = 'ß'.encode_utf8(&mut b);
346     ///
347     /// assert_eq!(result, None);
348     /// ```
349     #[stable(feature = "rust1", since = "1.0.0")]
350     fn encode_utf16(self, dst: &mut [u16]) -> Option<uint>;
351 }
352
353 #[stable(feature = "rust1", since = "1.0.0")]
354 impl CharExt for char {
355     #[unstable(feature = "core",
356                reason = "pending integer conventions")]
357     fn is_digit(self, radix: uint) -> bool {
358         self.to_digit(radix).is_some()
359     }
360
361     #[unstable(feature = "core",
362                reason = "pending integer conventions")]
363     fn to_digit(self, radix: uint) -> Option<uint> {
364         if radix > 36 {
365             panic!("to_digit: radix is too high (maximum 36)");
366         }
367         let val = match self {
368           '0' ... '9' => self as uint - ('0' as uint),
369           'a' ... 'z' => self as uint + 10 - ('a' as uint),
370           'A' ... 'Z' => self as uint + 10 - ('A' as uint),
371           _ => return None,
372         };
373         if val < radix { Some(val) }
374         else { None }
375     }
376
377     #[stable(feature = "rust1", since = "1.0.0")]
378     fn escape_unicode(self) -> EscapeUnicode {
379         EscapeUnicode { c: self, state: EscapeUnicodeState::Backslash }
380     }
381
382     #[stable(feature = "rust1", since = "1.0.0")]
383     fn escape_default(self) -> EscapeDefault {
384         let init_state = match self {
385             '\t' => EscapeDefaultState::Backslash('t'),
386             '\r' => EscapeDefaultState::Backslash('r'),
387             '\n' => EscapeDefaultState::Backslash('n'),
388             '\\' => EscapeDefaultState::Backslash('\\'),
389             '\'' => EscapeDefaultState::Backslash('\''),
390             '"'  => EscapeDefaultState::Backslash('"'),
391             '\x20' ... '\x7e' => EscapeDefaultState::Char(self),
392             _ => EscapeDefaultState::Unicode(self.escape_unicode())
393         };
394         EscapeDefault { state: init_state }
395     }
396
397     #[inline]
398     #[stable(feature = "rust1", since = "1.0.0")]
399     fn len_utf8(self) -> uint {
400         let code = self as u32;
401         match () {
402             _ if code < MAX_ONE_B   => 1,
403             _ if code < MAX_TWO_B   => 2,
404             _ if code < MAX_THREE_B => 3,
405             _  => 4,
406         }
407     }
408
409     #[inline]
410     #[stable(feature = "rust1", since = "1.0.0")]
411     fn len_utf16(self) -> uint {
412         let ch = self as u32;
413         if (ch & 0xFFFF_u32) == ch { 1 } else { 2 }
414     }
415
416     #[inline]
417     #[unstable(feature = "core",
418                reason = "pending decision about Iterator/Writer/Reader")]
419     fn encode_utf8(self, dst: &mut [u8]) -> Option<uint> {
420         encode_utf8_raw(self as u32, dst)
421     }
422
423     #[inline]
424     #[unstable(feature = "core",
425                reason = "pending decision about Iterator/Writer/Reader")]
426     fn encode_utf16(self, dst: &mut [u16]) -> Option<uint> {
427         encode_utf16_raw(self as u32, dst)
428     }
429 }
430
431 /// Encodes a raw u32 value as UTF-8 into the provided byte buffer,
432 /// and then returns the number of bytes written.
433 ///
434 /// If the buffer is not large enough, nothing will be written into it
435 /// and a `None` will be returned.
436 #[inline]
437 #[unstable(feature = "core")]
438 pub fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> Option<uint> {
439     // Marked #[inline] to allow llvm optimizing it away
440     if code < MAX_ONE_B && dst.len() >= 1 {
441         dst[0] = code as u8;
442         Some(1)
443     } else if code < MAX_TWO_B && dst.len() >= 2 {
444         dst[0] = (code >> 6u & 0x1F_u32) as u8 | TAG_TWO_B;
445         dst[1] = (code & 0x3F_u32) as u8 | TAG_CONT;
446         Some(2)
447     } else if code < MAX_THREE_B && dst.len() >= 3  {
448         dst[0] = (code >> 12u & 0x0F_u32) as u8 | TAG_THREE_B;
449         dst[1] = (code >>  6u & 0x3F_u32) as u8 | TAG_CONT;
450         dst[2] = (code & 0x3F_u32) as u8 | TAG_CONT;
451         Some(3)
452     } else if dst.len() >= 4 {
453         dst[0] = (code >> 18u & 0x07_u32) as u8 | TAG_FOUR_B;
454         dst[1] = (code >> 12u & 0x3F_u32) as u8 | TAG_CONT;
455         dst[2] = (code >>  6u & 0x3F_u32) as u8 | TAG_CONT;
456         dst[3] = (code & 0x3F_u32) as u8 | TAG_CONT;
457         Some(4)
458     } else {
459         None
460     }
461 }
462
463 /// Encodes a raw u32 value as UTF-16 into the provided `u16` buffer,
464 /// and then returns the number of `u16`s written.
465 ///
466 /// If the buffer is not large enough, nothing will be written into it
467 /// and a `None` will be returned.
468 #[inline]
469 #[unstable(feature = "core")]
470 pub fn encode_utf16_raw(mut ch: u32, dst: &mut [u16]) -> Option<uint> {
471     // Marked #[inline] to allow llvm optimizing it away
472     if (ch & 0xFFFF_u32) == ch  && dst.len() >= 1 {
473         // The BMP falls through (assuming non-surrogate, as it should)
474         dst[0] = ch as u16;
475         Some(1)
476     } else if dst.len() >= 2 {
477         // Supplementary planes break into surrogates.
478         ch -= 0x1_0000_u32;
479         dst[0] = 0xD800_u16 | ((ch >> 10) as u16);
480         dst[1] = 0xDC00_u16 | ((ch as u16) & 0x3FF_u16);
481         Some(2)
482     } else {
483         None
484     }
485 }
486
487 /// An iterator over the characters that represent a `char`, as escaped by
488 /// Rust's unicode escaping rules.
489 #[derive(Clone)]
490 #[stable(feature = "rust1", since = "1.0.0")]
491 pub struct EscapeUnicode {
492     c: char,
493     state: EscapeUnicodeState
494 }
495
496 #[derive(Clone)]
497 #[unstable(feature = "core")]
498 enum EscapeUnicodeState {
499     Backslash,
500     Type,
501     LeftBrace,
502     Value(uint),
503     RightBrace,
504     Done,
505 }
506
507 #[stable(feature = "rust1", since = "1.0.0")]
508 impl Iterator for EscapeUnicode {
509     type Item = char;
510
511     fn next(&mut self) -> Option<char> {
512         match self.state {
513             EscapeUnicodeState::Backslash => {
514                 self.state = EscapeUnicodeState::Type;
515                 Some('\\')
516             }
517             EscapeUnicodeState::Type => {
518                 self.state = EscapeUnicodeState::LeftBrace;
519                 Some('u')
520             }
521             EscapeUnicodeState::LeftBrace => {
522                 let mut n = 0;
523                 while (self.c as u32) >> (4 * (n + 1)) != 0 {
524                     n += 1;
525                 }
526                 self.state = EscapeUnicodeState::Value(n);
527                 Some('{')
528             }
529             EscapeUnicodeState::Value(offset) => {
530                 let v = match ((self.c as i32) >> (offset * 4)) & 0xf {
531                     i @ 0 ... 9 => '0' as i32 + i,
532                     i => 'a' as i32 + (i - 10)
533                 };
534                 if offset == 0 {
535                     self.state = EscapeUnicodeState::RightBrace;
536                 } else {
537                     self.state = EscapeUnicodeState::Value(offset - 1);
538                 }
539                 Some(unsafe { transmute(v) })
540             }
541             EscapeUnicodeState::RightBrace => {
542                 self.state = EscapeUnicodeState::Done;
543                 Some('}')
544             }
545             EscapeUnicodeState::Done => None,
546         }
547     }
548 }
549
550 /// An iterator over the characters that represent a `char`, escaped
551 /// for maximum portability.
552 #[derive(Clone)]
553 #[stable(feature = "rust1", since = "1.0.0")]
554 pub struct EscapeDefault {
555     state: EscapeDefaultState
556 }
557
558 #[derive(Clone)]
559 #[unstable(feature = "core")]
560 enum EscapeDefaultState {
561     Backslash(char),
562     Char(char),
563     Done,
564     Unicode(EscapeUnicode),
565 }
566
567 #[stable(feature = "rust1", since = "1.0.0")]
568 impl Iterator for EscapeDefault {
569     type Item = char;
570
571     fn next(&mut self) -> Option<char> {
572         match self.state {
573             EscapeDefaultState::Backslash(c) => {
574                 self.state = EscapeDefaultState::Char(c);
575                 Some('\\')
576             }
577             EscapeDefaultState::Char(c) => {
578                 self.state = EscapeDefaultState::Done;
579                 Some(c)
580             }
581             EscapeDefaultState::Done => None,
582             EscapeDefaultState::Unicode(ref mut iter) => iter.next()
583         }
584     }
585 }