authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-10-31 12:06:42+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-11-02 14:13:06-05:00
log35a8d90e55da56ac6ba8e104302791421eb62253
treed7eff8347a9518d245f594f9f4af05651db0e83b
parent00ceb592ef8d396ec354152c1684321a6c5847e4

std: Make parseInt/parseUnsigned detect the radix


1 files changed, 62 insertions(+), 3 deletions(-)

lib/std/fmt.zig+62-3
...@@ -1059,6 +1059,16 @@ pub const ParseIntError = error{...@@ -1059,6 +1059,16 @@ pub const ParseIntError = error{
1059 InvalidCharacter,1059 InvalidCharacter,
1060};1060};
10611061
1062/// Parses the string `buf` as signed or unsigned representation in the
1063/// specified radix of an integral value of type `T`.
1064///
1065/// When `radix` is zero the string prefix is examined to detect the true radix:
1066/// * A prefix of "0b" implies radix=2,
1067/// * A prefix of "0o" implies radix=8,
1068/// * A prefix of "0x" implies radix=16,
1069/// * Otherwise radix=10 is assumed.
1070///
1071/// See also `parseUnsigned`.
1062pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) ParseIntError!T {1072pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) ParseIntError!T {
1063 if (buf.len == 0) return error.InvalidCharacter;1073 if (buf.len == 0) return error.InvalidCharacter;
1064 if (buf[0] == '+') return parseWithSign(T, buf[1..], radix, .Pos);1074 if (buf[0] == '+') return parseWithSign(T, buf[1..], radix, .Pos);
...@@ -1091,6 +1101,20 @@ test "parseInt" {...@@ -1091,6 +1101,20 @@ test "parseInt" {
1091 std.testing.expectError(error.InvalidCharacter, parseInt(i32, "+", 10));1101 std.testing.expectError(error.InvalidCharacter, parseInt(i32, "+", 10));
1092 std.testing.expectError(error.InvalidCharacter, parseInt(u32, "-", 10));1102 std.testing.expectError(error.InvalidCharacter, parseInt(u32, "-", 10));
1093 std.testing.expectError(error.InvalidCharacter, parseInt(i32, "-", 10));1103 std.testing.expectError(error.InvalidCharacter, parseInt(i32, "-", 10));
1104
1105 // autodectect the radix
1106 std.testing.expect((try parseInt(i32, "111", 0)) == 111);
1107 std.testing.expect((try parseInt(i32, "+0b111", 0)) == 7);
1108 std.testing.expect((try parseInt(i32, "+0o111", 0)) == 73);
1109 std.testing.expect((try parseInt(i32, "+0x111", 0)) == 273);
1110 std.testing.expect((try parseInt(i32, "-0b111", 0)) == -7);
1111 std.testing.expect((try parseInt(i32, "-0o111", 0)) == -73);
1112 std.testing.expect((try parseInt(i32, "-0x111", 0)) == -273);
1113
1114 // bare binary/octal/decimal prefix is invalid
1115 std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0b", 0));
1116 std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0o", 0));
1117 std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0x", 0));
1094}1118}
10951119
1096fn parseWithSign(1120fn parseWithSign(
...@@ -1101,6 +1125,31 @@ fn parseWithSign(...@@ -1101,6 +1125,31 @@ fn parseWithSign(
1101) ParseIntError!T {1125) ParseIntError!T {
1102 if (buf.len == 0) return error.InvalidCharacter;1126 if (buf.len == 0) return error.InvalidCharacter;
11031127
1128 var buf_radix = radix;
1129 var buf_start = buf;
1130 if (radix == 0) {
1131 // Treat is as a decimal number by default.
1132 buf_radix = 10;
1133 // Detect the radix by looking at buf prefix.
1134 if (buf.len > 2 and buf[0] == '0') {
1135 switch (buf[1]) {
1136 'b' => {
1137 buf_radix = 2;
1138 buf_start = buf[2..];
1139 },
1140 'o' => {
1141 buf_radix = 8;
1142 buf_start = buf[2..];
1143 },
1144 'x' => {
1145 buf_radix = 16;
1146 buf_start = buf[2..];
1147 },
1148 else => {},
1149 }
1150 }
1151 }
1152
1104 const add = switch (sign) {1153 const add = switch (sign) {
1105 .Pos => math.add,1154 .Pos => math.add,
1106 .Neg => math.sub,1155 .Neg => math.sub,
...@@ -1108,16 +1157,26 @@ fn parseWithSign(...@@ -1108,16 +1157,26 @@ fn parseWithSign(
11081157
1109 var x: T = 0;1158 var x: T = 0;
11101159
1111 for (buf) |c| {1160 for (buf_start) |c| {
1112 const digit = try charToDigit(c, radix);1161 const digit = try charToDigit(c, buf_radix);
11131162
1114 if (x != 0) x = try math.mul(T, x, try math.cast(T, radix));1163 if (x != 0) x = try math.mul(T, x, try math.cast(T, buf_radix));
1115 x = try add(T, x, try math.cast(T, digit));1164 x = try add(T, x, try math.cast(T, digit));
1116 }1165 }
11171166
1118 return x;1167 return x;
1119}1168}
11201169
1170/// Parses the string `buf` as unsigned representation in the specified radix
1171/// of an integral value of type `T`.
1172///
1173/// When `radix` is zero the string prefix is examined to detect the true radix:
1174/// * A prefix of "0b" implies radix=2,
1175/// * A prefix of "0o" implies radix=8,
1176/// * A prefix of "0x" implies radix=16,
1177/// * Otherwise radix=10 is assumed.
1178///
1179/// See also `parseInt`.
1121pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseIntError!T {1180pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseIntError!T {
1122 return parseWithSign(T, buf, radix, .Pos);1181 return parseWithSign(T, buf, radix, .Pos);
1123}1182}