Skip to content

Commit 41c6f67

Browse files
committed
libcore: from_str_common: provide option to ignore underscores.
Implement the possible improvement listed in the comment on from_str_bytes_common.
1 parent 49cdf36 commit 41c6f67

File tree

6 files changed

+44
-24
lines changed

6 files changed

+44
-24
lines changed

Diff for: src/libcore/num/f32.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ impl num::ToStrRadix for f32 {
507507
#[inline(always)]
508508
pub fn from_str(num: &str) -> Option<f32> {
509509
strconv::from_str_common(num, 10u, true, true, true,
510-
strconv::ExpDec, false)
510+
strconv::ExpDec, false, false)
511511
}
512512

513513
/**
@@ -540,7 +540,7 @@ pub fn from_str(num: &str) -> Option<f32> {
540540
#[inline(always)]
541541
pub fn from_str_hex(num: &str) -> Option<f32> {
542542
strconv::from_str_common(num, 16u, true, true, true,
543-
strconv::ExpBin, false)
543+
strconv::ExpBin, false, false)
544544
}
545545

546546
/**
@@ -565,7 +565,7 @@ pub fn from_str_hex(num: &str) -> Option<f32> {
565565
#[inline(always)]
566566
pub fn from_str_radix(num: &str, rdx: uint) -> Option<f32> {
567567
strconv::from_str_common(num, rdx, true, true, false,
568-
strconv::ExpNone, false)
568+
strconv::ExpNone, false, false)
569569
}
570570

571571
impl from_str::FromStr for f32 {

Diff for: src/libcore/num/f64.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ impl num::ToStrRadix for f64 {
529529
#[inline(always)]
530530
pub fn from_str(num: &str) -> Option<f64> {
531531
strconv::from_str_common(num, 10u, true, true, true,
532-
strconv::ExpDec, false)
532+
strconv::ExpDec, false, false)
533533
}
534534

535535
/**
@@ -562,7 +562,7 @@ pub fn from_str(num: &str) -> Option<f64> {
562562
#[inline(always)]
563563
pub fn from_str_hex(num: &str) -> Option<f64> {
564564
strconv::from_str_common(num, 16u, true, true, true,
565-
strconv::ExpBin, false)
565+
strconv::ExpBin, false, false)
566566
}
567567

568568
/**
@@ -587,7 +587,7 @@ pub fn from_str_hex(num: &str) -> Option<f64> {
587587
#[inline(always)]
588588
pub fn from_str_radix(num: &str, rdx: uint) -> Option<f64> {
589589
strconv::from_str_common(num, rdx, true, true, false,
590-
strconv::ExpNone, false)
590+
strconv::ExpNone, false, false)
591591
}
592592

593593
impl from_str::FromStr for f64 {

Diff for: src/libcore/num/float.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ impl num::ToStrRadix for float {
242242
#[inline(always)]
243243
pub fn from_str(num: &str) -> Option<float> {
244244
strconv::from_str_common(num, 10u, true, true, true,
245-
strconv::ExpDec, false)
245+
strconv::ExpDec, false, false)
246246
}
247247
248248
/**
@@ -275,7 +275,7 @@ pub fn from_str(num: &str) -> Option<float> {
275275
#[inline(always)]
276276
pub fn from_str_hex(num: &str) -> Option<float> {
277277
strconv::from_str_common(num, 16u, true, true, true,
278-
strconv::ExpBin, false)
278+
strconv::ExpBin, false, false)
279279
}
280280
281281
/**
@@ -300,7 +300,7 @@ pub fn from_str_hex(num: &str) -> Option<float> {
300300
#[inline(always)]
301301
pub fn from_str_radix(num: &str, radix: uint) -> Option<float> {
302302
strconv::from_str_common(num, radix, true, true, false,
303-
strconv::ExpNone, false)
303+
strconv::ExpNone, false, false)
304304
}
305305
306306
impl from_str::FromStr for float {

Diff for: src/libcore/num/int-template.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -202,21 +202,21 @@ impl ops::Neg<T> for T {
202202
#[inline(always)]
203203
pub fn from_str(s: &str) -> Option<T> {
204204
strconv::from_str_common(s, 10u, true, false, false,
205-
strconv::ExpNone, false)
205+
strconv::ExpNone, false, false)
206206
}
207207
208208
/// Parse a string as a number in the given base.
209209
#[inline(always)]
210210
pub fn from_str_radix(s: &str, radix: uint) -> Option<T> {
211211
strconv::from_str_common(s, radix, true, false, false,
212-
strconv::ExpNone, false)
212+
strconv::ExpNone, false, false)
213213
}
214214
215215
/// Parse a byte slice as a number in the given base.
216216
#[inline(always)]
217217
pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<T> {
218218
strconv::from_str_bytes_common(buf, radix, true, false, false,
219-
strconv::ExpNone, false)
219+
strconv::ExpNone, false, false)
220220
}
221221
222222
impl FromStr for T {

Diff for: src/libcore/num/strconv.rs

+29-9
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,8 @@ priv static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
429429
* `FFp128`. The exponent string itself is always base 10.
430430
* Can conflict with `radix`, see Failure.
431431
* - `empty_zero` - Whether to accept a empty `buf` as a 0 or not.
432+
* - `ignore_underscores` - Whether all underscores within the string should
433+
* be ignored.
432434
*
433435
* # Return value
434436
* Returns `Some(n)` if `buf` parses to a number n without overflowing, and
@@ -443,16 +445,13 @@ priv static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
443445
* between digit and exponent sign `'p'`.
444446
* - Fails if `radix` > 18 and `special == true` due to conflict
445447
* between digit and lowest first character in `inf` and `NaN`, the `'i'`.
446-
*
447-
* # Possible improvements
448-
* - Could accept option to allow ignoring underscores, allowing for numbers
449-
* formated like `FF_AE_FF_FF`.
450448
*/
451449
pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+
452450
Mul<T,T>+Sub<T,T>+Neg<T>+Add<T,T>+
453451
NumStrConv>(
454452
buf: &[u8], radix: uint, negative: bool, fractional: bool,
455-
special: bool, exponent: ExponentFormat, empty_zero: bool
453+
special: bool, exponent: ExponentFormat, empty_zero: bool,
454+
ignore_underscores: bool
456455
) -> Option<T> {
457456
match exponent {
458457
ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e'
@@ -540,6 +539,7 @@ pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+
540539
last_accum = accum;
541540
}
542541
None => match c {
542+
'_' if ignore_underscores => {}
543543
'e' | 'E' | 'p' | 'P' => {
544544
exp_found = true;
545545
break; // start of exponent
@@ -583,6 +583,7 @@ pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+
583583
last_accum = accum;
584584
}
585585
None => match c {
586+
'_' if ignore_underscores => {}
586587
'e' | 'E' | 'p' | 'P' => {
587588
exp_found = true;
588589
break; // start of exponent
@@ -610,6 +611,7 @@ pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+
610611
if exp_found {
611612
let c = buf[i] as char;
612613
let base = match (c, exponent) {
614+
// c is never _ so don't need to handle specially
613615
('e', ExpDec) | ('E', ExpDec) => 10u,
614616
('p', ExpBin) | ('P', ExpBin) => 2u,
615617
_ => return None // char doesn't fit given exponent format
@@ -618,7 +620,8 @@ pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+
618620
// parse remaining bytes as decimal integer,
619621
// skipping the exponent char
620622
let exp: Option<int> = from_str_bytes_common(
621-
buf.slice(i+1, len), 10, true, false, false, ExpNone, false);
623+
buf.slice(i+1, len), 10, true, false, false, ExpNone, false,
624+
ignore_underscores);
622625

623626
match exp {
624627
Some(exp_pow) => {
@@ -643,24 +646,41 @@ pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+
643646
pub fn from_str_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+Mul<T,T>+
644647
Sub<T,T>+Neg<T>+Add<T,T>+NumStrConv>(
645648
buf: &str, radix: uint, negative: bool, fractional: bool,
646-
special: bool, exponent: ExponentFormat, empty_zero: bool
649+
special: bool, exponent: ExponentFormat, empty_zero: bool,
650+
ignore_underscores: bool
647651
) -> Option<T> {
648652
from_str_bytes_common(str::to_bytes(buf), radix, negative,
649-
fractional, special, exponent, empty_zero)
653+
fractional, special, exponent, empty_zero,
654+
ignore_underscores)
650655
}
651656

652657
#[cfg(test)]
653658
mod test {
654659
use super::*;
655660
use option::*;
656661

662+
#[test]
663+
fn from_str_ignore_underscores() {
664+
let s : Option<u8> = from_str_common("__1__", 2, false, false, false,
665+
ExpNone, false, true);
666+
assert_eq!(s, Some(1u8));
667+
668+
let n : Option<u8> = from_str_common("__1__", 2, false, false, false,
669+
ExpNone, false, false);
670+
assert_eq!(n, None);
671+
672+
let f : Option<f32> = from_str_common("_1_._1_e_1_", 10, false, true, false,
673+
ExpDec, false, true);
674+
assert_eq!(f, Some(1.1e1f32));
675+
}
676+
657677
#[test]
658678
fn from_str_issue5770() {
659679
// try to parse 0b1_1111_1111 = 511 as a u8. Caused problems
660680
// since 255*2+1 == 255 (mod 256) so the overflow wasn't
661681
// detected.
662682
let n : Option<u8> = from_str_common("111111111", 2, false, false, false,
663-
ExpNone, false);
683+
ExpNone, false, false);
664684
assert_eq!(n, None);
665685
}
666686
}

Diff for: src/libcore/num/uint-template.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -168,21 +168,21 @@ impl ops::Neg<T> for T {
168168
#[inline(always)]
169169
pub fn from_str(s: &str) -> Option<T> {
170170
strconv::from_str_common(s, 10u, false, false, false,
171-
strconv::ExpNone, false)
171+
strconv::ExpNone, false, false)
172172
}
173173
174174
/// Parse a string as a number in the given base.
175175
#[inline(always)]
176176
pub fn from_str_radix(s: &str, radix: uint) -> Option<T> {
177177
strconv::from_str_common(s, radix, false, false, false,
178-
strconv::ExpNone, false)
178+
strconv::ExpNone, false, false)
179179
}
180180
181181
/// Parse a byte slice as a number in the given base.
182182
#[inline(always)]
183183
pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<T> {
184184
strconv::from_str_bytes_common(buf, radix, false, false, false,
185-
strconv::ExpNone, false)
185+
strconv::ExpNone, false, false)
186186
}
187187
188188
impl FromStr for T {

0 commit comments

Comments
 (0)