| ... | @@ -1059,6 +1059,16 @@ pub const ParseIntError = error{ | ... | @@ -1059,6 +1059,16 @@ pub const ParseIntError = error{ |
| 1059 | InvalidCharacter, | 1059 | InvalidCharacter, |
| 1060 | }; | 1060 | }; |
| 1061 | | 1061 | |
| | 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`. |
| 1062 | pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) ParseIntError!T { | 1072 | pub 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 | } |
| 1095 | | 1119 | |
| 1096 | fn parseWithSign( | 1120 | fn 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; |
| 1103 | | 1127 | |
| | 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( |
| 1108 | | 1157 | |
| 1109 | var x: T = 0; | 1158 | var x: T = 0; |
| 1110 | | 1159 | |
| 1111 | for (buf) |c| { | 1160 | for (buf_start) |c| { |
| 1112 | const digit = try charToDigit(c, radix); | 1161 | const digit = try charToDigit(c, buf_radix); |
| 1113 | | 1162 | |
| 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 | } |
| 1117 | | 1166 | |
| 1118 | return x; | 1167 | return x; |
| 1119 | } | 1168 | } |
| 1120 | | 1169 | |
| | 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`. |
| 1121 | pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseIntError!T { | 1180 | pub 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 | } |