malachite_nz/integer/conversion/string/from_string.rs
1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::integer::Integer;
10use crate::natural::Natural;
11use core::ops::Neg;
12use core::str::FromStr;
13use malachite_base::num::conversion::traits::FromStringBase;
14
15impl FromStr for Integer {
16 type Err = ();
17
18 /// Converts an string to an [`Integer`].
19 ///
20 /// If the string does not represent a valid [`Integer`], an `Err` is returned. To be valid, the
21 /// string must be nonempty and only contain the [`char`]s `'0'` through `'9'`, with an optional
22 /// single leading `'-'` or `'+'`. Leading zeros are allowed, as are the strings `"-0"` and
23 /// `"+0"`. The strings `"-"` and `"+"` are not.
24 ///
25 /// # Worst-case complexity
26 /// $T(n) = O(n (\log n)^2 \log\log n)$
27 ///
28 /// $M(n) = O(n \log n)$
29 ///
30 /// where $T$ is time, $M$ is additional memory, and $n$ is `s.len()`.
31 ///
32 /// # Examples
33 /// ```
34 /// use core::str::FromStr;
35 /// use malachite_nz::integer::Integer;
36 ///
37 /// assert_eq!(Integer::from_str("123456").unwrap(), 123456);
38 /// assert_eq!(Integer::from_str("00123456").unwrap(), 123456);
39 /// assert_eq!(Integer::from_str("0").unwrap(), 0);
40 /// assert_eq!(Integer::from_str("-123456").unwrap(), -123456);
41 /// assert_eq!(Integer::from_str("-00123456").unwrap(), -123456);
42 /// assert_eq!(Integer::from_str("-0").unwrap(), 0);
43 /// assert_eq!(Integer::from_str("+123456").unwrap(), 123456);
44 /// assert_eq!(Integer::from_str("+0").unwrap(), 0);
45 ///
46 /// assert!(Integer::from_str("").is_err());
47 /// assert!(Integer::from_str("a").is_err());
48 /// assert!(Integer::from_str("+").is_err());
49 /// assert!(Integer::from_str("+-5").is_err());
50 /// ```
51 #[inline]
52 fn from_str(s: &str) -> Result<Self, ()> {
53 Self::from_string_base(10, s).ok_or(())
54 }
55}
56
57impl FromStringBase for Integer {
58 /// Converts an string, in a specified base, to an [`Integer`].
59 ///
60 /// If the string does not represent a valid [`Integer`], an `Err` is returned. To be valid, the
61 /// string must be nonempty and only contain the [`char`]s `'0'` through `'9'`, `'a'` through
62 /// `'z'`, and `'A'` through `'Z'`, with an optional single leading `'-'` or `'+'`; and only
63 /// characters that represent digits smaller than the base are allowed. Leading zeros are
64 /// allowed, as is the string `"-0"`. The string `"-"` is not.
65 ///
66 /// # Worst-case complexity
67 /// $T(n) = O(n (\log n)^2 \log\log n)$
68 ///
69 /// $M(n) = O(n \log n)$
70 ///
71 /// where $T$ is time, $M$ is additional memory, and $n$ is `s.len()`.
72 ///
73 /// # Panics
74 /// Panics if `base` is less than 2 or greater than 62.
75 ///
76 /// # Examples
77 /// ```
78 /// use malachite_base::num::conversion::traits::FromStringBase;
79 /// use malachite_nz::integer::Integer;
80 ///
81 /// assert_eq!(Integer::from_string_base(10, "123456").unwrap(), 123456);
82 /// assert_eq!(Integer::from_string_base(10, "00123456").unwrap(), 123456);
83 /// assert_eq!(Integer::from_string_base(16, "0").unwrap(), 0);
84 /// assert_eq!(
85 /// Integer::from_string_base(16, "deadbeef").unwrap(),
86 /// 3735928559i64
87 /// );
88 /// assert_eq!(
89 /// Integer::from_string_base(16, "deAdBeEf").unwrap(),
90 /// 3735928559i64
91 /// );
92 /// assert_eq!(Integer::from_string_base(10, "-123456").unwrap(), -123456);
93 /// assert_eq!(Integer::from_string_base(10, "-00123456").unwrap(), -123456);
94 ///
95 /// // above base 36, the uppercase and lowercase letters are distinct digits
96 /// assert_eq!(Integer::from_string_base(62, "-G8").unwrap(), -1000);
97 /// assert_eq!(Integer::from_string_base(62, "-g8").unwrap(), -2612);
98 /// assert_eq!(Integer::from_string_base(16, "-0").unwrap(), 0);
99 /// assert_eq!(
100 /// Integer::from_string_base(16, "-deadbeef").unwrap(),
101 /// -3735928559i64
102 /// );
103 /// assert_eq!(
104 /// Integer::from_string_base(16, "-deAdBeEf").unwrap(),
105 /// -3735928559i64
106 /// );
107 ///
108 /// assert!(Integer::from_string_base(10, "").is_none());
109 /// assert!(Integer::from_string_base(10, "a").is_none());
110 /// assert!(Integer::from_string_base(2, "2").is_none());
111 /// assert!(Integer::from_string_base(2, "-2").is_none());
112 /// ```
113 #[inline]
114 fn from_string_base(base: u8, s: &str) -> Option<Self> {
115 if let Some(abs_string) = s.strip_prefix('-') {
116 if abs_string.starts_with('+') {
117 None
118 } else {
119 Natural::from_string_base(base, abs_string).map(Neg::neg)
120 }
121 } else {
122 Natural::from_string_base(base, s).map(Self::from)
123 }
124 }
125}