| ... | @@ -235,6 +235,22 @@ pub const Utf8Iterator = struct { | ... | @@ -235,6 +235,22 @@ pub const Utf8Iterator = struct { |
| 235 | else => unreachable, | 235 | else => unreachable, |
| 236 | } | 236 | } |
| 237 | } | 237 | } |
| | 238 | |
| | 239 | /// Look ahead at the next n codepoints without advancing the iterator. |
| | 240 | /// If fewer than n codepoints are available, then return the remainder of the string. |
| | 241 | pub fn peek(it: *Utf8Iterator, n: usize) []const u8 { |
| | 242 | const original_i = it.i; |
| | 243 | defer it.i = original_i; |
| | 244 | |
| | 245 | var end_ix = original_i; |
| | 246 | var found: usize = 0; |
| | 247 | while (found < n) : (found += 1) { |
| | 248 | const next_codepoint = it.nextCodepointSlice() orelse return it.bytes[original_i..]; |
| | 249 | end_ix += next_codepoint.len; |
| | 250 | } |
| | 251 | |
| | 252 | return it.bytes[original_i..end_ix]; |
| | 253 | } |
| 238 | }; | 254 | }; |
| 239 | | 255 | |
| 240 | pub const Utf16LeIterator = struct { | 256 | pub const Utf16LeIterator = struct { |
| ... | @@ -451,6 +467,31 @@ fn testMiscInvalidUtf8() void { | ... | @@ -451,6 +467,31 @@ fn testMiscInvalidUtf8() void { |
| 451 | testValid("\xee\x80\x80", 0xe000); | 467 | testValid("\xee\x80\x80", 0xe000); |
| 452 | } | 468 | } |
| 453 | | 469 | |
| | 470 | test "utf8 iterator peeking" { |
| | 471 | comptime testUtf8Peeking(); |
| | 472 | testUtf8Peeking(); |
| | 473 | } |
| | 474 | |
| | 475 | fn testUtf8Peeking() void { |
| | 476 | const s = Utf8View.initComptime("noël"); |
| | 477 | var it = s.iterator(); |
| | 478 | |
| | 479 | testing.expect(std.mem.eql(u8, "n", it.nextCodepointSlice().?)); |
| | 480 | |
| | 481 | testing.expect(std.mem.eql(u8, "o", it.peek(1))); |
| | 482 | testing.expect(std.mem.eql(u8, "oë", it.peek(2))); |
| | 483 | testing.expect(std.mem.eql(u8, "oël", it.peek(3))); |
| | 484 | testing.expect(std.mem.eql(u8, "oël", it.peek(4))); |
| | 485 | testing.expect(std.mem.eql(u8, "oël", it.peek(10))); |
| | 486 | |
| | 487 | testing.expect(std.mem.eql(u8, "o", it.nextCodepointSlice().?)); |
| | 488 | testing.expect(std.mem.eql(u8, "ë", it.nextCodepointSlice().?)); |
| | 489 | testing.expect(std.mem.eql(u8, "l", it.nextCodepointSlice().?)); |
| | 490 | testing.expect(it.nextCodepointSlice() == null); |
| | 491 | |
| | 492 | testing.expect(std.mem.eql(u8, &[_]u8{}, it.peek(1))); |
| | 493 | } |
| | 494 | |
| 454 | fn testError(bytes: []const u8, expected_err: anyerror) void { | 495 | fn testError(bytes: []const u8, expected_err: anyerror) void { |
| 455 | testing.expectError(expected_err, testDecode(bytes)); | 496 | testing.expectError(expected_err, testDecode(bytes)); |
| 456 | } | 497 | } |