| ... | ... | @@ -1707,23 +1707,32 @@ pub fn split(comptime T: type, buffer: []const T, delimiter: []const T) SplitIte |
| 1707 | 1707 | |
| 1708 | 1708 | test "split" { |
| 1709 | 1709 | var it = split(u8, "abc|def||ghi", "|"); |
| 1710 | | try testing.expect(eql(u8, it.next().?, "abc")); |
| 1711 | | try testing.expect(eql(u8, it.next().?, "def")); |
| 1712 | | try testing.expect(eql(u8, it.next().?, "")); |
| 1713 | | try testing.expect(eql(u8, it.next().?, "ghi")); |
| 1710 | try testing.expectEqualSlices(u8, it.rest(), "abc|def||ghi"); |
| 1711 | try testing.expectEqualSlices(u8, it.next().?, "abc"); |
| 1712 | |
| 1713 | try testing.expectEqualSlices(u8, it.rest(), "def||ghi"); |
| 1714 | try testing.expectEqualSlices(u8, it.next().?, "def"); |
| 1715 | |
| 1716 | try testing.expectEqualSlices(u8, it.rest(), "|ghi"); |
| 1717 | try testing.expectEqualSlices(u8, it.next().?, ""); |
| 1718 | |
| 1719 | try testing.expectEqualSlices(u8, it.rest(), "ghi"); |
| 1720 | try testing.expectEqualSlices(u8, it.next().?, "ghi"); |
| 1721 | |
| 1722 | try testing.expectEqualSlices(u8, it.rest(), ""); |
| 1714 | 1723 | try testing.expect(it.next() == null); |
| 1715 | 1724 | |
| 1716 | 1725 | it = split(u8, "", "|"); |
| 1717 | | try testing.expect(eql(u8, it.next().?, "")); |
| 1726 | try testing.expectEqualSlices(u8, it.next().?, ""); |
| 1718 | 1727 | try testing.expect(it.next() == null); |
| 1719 | 1728 | |
| 1720 | 1729 | it = split(u8, "|", "|"); |
| 1721 | | try testing.expect(eql(u8, it.next().?, "")); |
| 1722 | | try testing.expect(eql(u8, it.next().?, "")); |
| 1730 | try testing.expectEqualSlices(u8, it.next().?, ""); |
| 1731 | try testing.expectEqualSlices(u8, it.next().?, ""); |
| 1723 | 1732 | try testing.expect(it.next() == null); |
| 1724 | 1733 | |
| 1725 | 1734 | it = split(u8, "hello", " "); |
| 1726 | | try testing.expect(eql(u8, it.next().?, "hello")); |
| 1735 | try testing.expectEqualSlices(u8, it.next().?, "hello"); |
| 1727 | 1736 | try testing.expect(it.next() == null); |
| 1728 | 1737 | |
| 1729 | 1738 | var it16 = split( |
| ... | ... | @@ -1731,17 +1740,18 @@ test "split" { |
| 1731 | 1740 | std.unicode.utf8ToUtf16LeStringLiteral("hello"), |
| 1732 | 1741 | std.unicode.utf8ToUtf16LeStringLiteral(" "), |
| 1733 | 1742 | ); |
| 1734 | | try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("hello"))); |
| 1743 | try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("hello")); |
| 1735 | 1744 | try testing.expect(it16.next() == null); |
| 1736 | 1745 | } |
| 1737 | 1746 | |
| 1738 | 1747 | test "split (multibyte)" { |
| 1739 | 1748 | var it = split(u8, "a, b ,, c, d, e", ", "); |
| 1740 | | try testing.expect(eql(u8, it.next().?, "a")); |
| 1741 | | try testing.expect(eql(u8, it.next().?, "b ,")); |
| 1742 | | try testing.expect(eql(u8, it.next().?, "c")); |
| 1743 | | try testing.expect(eql(u8, it.next().?, "d")); |
| 1744 | | try testing.expect(eql(u8, it.next().?, "e")); |
| 1749 | try testing.expectEqualSlices(u8, it.next().?, "a"); |
| 1750 | try testing.expectEqualSlices(u8, it.rest(), "b ,, c, d, e"); |
| 1751 | try testing.expectEqualSlices(u8, it.next().?, "b ,"); |
| 1752 | try testing.expectEqualSlices(u8, it.next().?, "c"); |
| 1753 | try testing.expectEqualSlices(u8, it.next().?, "d"); |
| 1754 | try testing.expectEqualSlices(u8, it.next().?, "e"); |
| 1745 | 1755 | try testing.expect(it.next() == null); |
| 1746 | 1756 | |
| 1747 | 1757 | var it16 = split( |
| ... | ... | @@ -1749,11 +1759,99 @@ test "split (multibyte)" { |
| 1749 | 1759 | std.unicode.utf8ToUtf16LeStringLiteral("a, b ,, c, d, e"), |
| 1750 | 1760 | std.unicode.utf8ToUtf16LeStringLiteral(", "), |
| 1751 | 1761 | ); |
| 1752 | | try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("a"))); |
| 1753 | | try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("b ,"))); |
| 1754 | | try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("c"))); |
| 1755 | | try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("d"))); |
| 1756 | | try testing.expect(eql(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("e"))); |
| 1762 | try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("a")); |
| 1763 | try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("b ,")); |
| 1764 | try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("c")); |
| 1765 | try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("d")); |
| 1766 | try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("e")); |
| 1767 | try testing.expect(it16.next() == null); |
| 1768 | } |
| 1769 | |
| 1770 | /// Returns an iterator that iterates backwards over the slices of `buffer` |
| 1771 | /// that are separated by bytes in `delimiter`. |
| 1772 | /// splitBackwards(u8, "abc|def||ghi", "|") |
| 1773 | /// will return slices for "ghi", "", "def", "abc", null, in that order. |
| 1774 | /// If `delimiter` does not exist in buffer, |
| 1775 | /// the iterator will return `buffer`, null, in that order. |
| 1776 | /// The delimiter length must not be zero. |
| 1777 | pub fn splitBackwards(comptime T: type, buffer: []const T, delimiter: []const T) SplitBackwardsIterator(T) { |
| 1778 | assert(delimiter.len != 0); |
| 1779 | return SplitBackwardsIterator(T){ |
| 1780 | .index = buffer.len, |
| 1781 | .buffer = buffer, |
| 1782 | .delimiter = delimiter, |
| 1783 | }; |
| 1784 | } |
| 1785 | |
| 1786 | test "splitBackwards" { |
| 1787 | var it = splitBackwards(u8, "abc|def||ghi", "|"); |
| 1788 | try testing.expectEqualSlices(u8, it.rest(), "abc|def||ghi"); |
| 1789 | try testing.expectEqualSlices(u8, it.next().?, "ghi"); |
| 1790 | |
| 1791 | try testing.expectEqualSlices(u8, it.rest(), "abc|def|"); |
| 1792 | try testing.expectEqualSlices(u8, it.next().?, ""); |
| 1793 | |
| 1794 | try testing.expectEqualSlices(u8, it.rest(), "abc|def"); |
| 1795 | try testing.expectEqualSlices(u8, it.next().?, "def"); |
| 1796 | |
| 1797 | try testing.expectEqualSlices(u8, it.rest(), "abc"); |
| 1798 | try testing.expectEqualSlices(u8, it.next().?, "abc"); |
| 1799 | |
| 1800 | try testing.expectEqualSlices(u8, it.rest(), ""); |
| 1801 | try testing.expect(it.next() == null); |
| 1802 | |
| 1803 | it = splitBackwards(u8, "", "|"); |
| 1804 | try testing.expectEqualSlices(u8, it.next().?, ""); |
| 1805 | try testing.expect(it.next() == null); |
| 1806 | |
| 1807 | it = splitBackwards(u8, "|", "|"); |
| 1808 | try testing.expectEqualSlices(u8, it.next().?, ""); |
| 1809 | try testing.expectEqualSlices(u8, it.next().?, ""); |
| 1810 | try testing.expect(it.next() == null); |
| 1811 | |
| 1812 | it = splitBackwards(u8, "hello", " "); |
| 1813 | try testing.expectEqualSlices(u8, it.next().?, "hello"); |
| 1814 | try testing.expect(it.next() == null); |
| 1815 | |
| 1816 | var it16 = splitBackwards( |
| 1817 | u16, |
| 1818 | std.unicode.utf8ToUtf16LeStringLiteral("hello"), |
| 1819 | std.unicode.utf8ToUtf16LeStringLiteral(" "), |
| 1820 | ); |
| 1821 | try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("hello")); |
| 1822 | try testing.expect(it16.next() == null); |
| 1823 | } |
| 1824 | |
| 1825 | test "splitBackwards (multibyte)" { |
| 1826 | var it = splitBackwards(u8, "a, b ,, c, d, e", ", "); |
| 1827 | try testing.expectEqualSlices(u8, it.rest(), "a, b ,, c, d, e"); |
| 1828 | try testing.expectEqualSlices(u8, it.next().?, "e"); |
| 1829 | |
| 1830 | try testing.expectEqualSlices(u8, it.rest(), "a, b ,, c, d"); |
| 1831 | try testing.expectEqualSlices(u8, it.next().?, "d"); |
| 1832 | |
| 1833 | try testing.expectEqualSlices(u8, it.rest(), "a, b ,, c"); |
| 1834 | try testing.expectEqualSlices(u8, it.next().?, "c"); |
| 1835 | |
| 1836 | try testing.expectEqualSlices(u8, it.rest(), "a, b ,"); |
| 1837 | try testing.expectEqualSlices(u8, it.next().?, "b ,"); |
| 1838 | |
| 1839 | try testing.expectEqualSlices(u8, it.rest(), "a"); |
| 1840 | try testing.expectEqualSlices(u8, it.next().?, "a"); |
| 1841 | |
| 1842 | try testing.expectEqualSlices(u8, it.rest(), ""); |
| 1843 | try testing.expect(it.next() == null); |
| 1844 | |
| 1845 | var it16 = splitBackwards( |
| 1846 | u16, |
| 1847 | std.unicode.utf8ToUtf16LeStringLiteral("a, b ,, c, d, e"), |
| 1848 | std.unicode.utf8ToUtf16LeStringLiteral(", "), |
| 1849 | ); |
| 1850 | try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("e")); |
| 1851 | try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("d")); |
| 1852 | try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("c")); |
| 1853 | try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("b ,")); |
| 1854 | try testing.expectEqualSlices(u16, it16.next().?, std.unicode.utf8ToUtf16LeStringLiteral("a")); |
| 1757 | 1855 | try testing.expect(it16.next() == null); |
| 1758 | 1856 | } |
| 1759 | 1857 | |
| ... | ... | @@ -1862,6 +1960,35 @@ pub fn SplitIterator(comptime T: type) type { |
| 1862 | 1960 | }; |
| 1863 | 1961 | } |
| 1864 | 1962 | |
| 1963 | pub fn SplitBackwardsIterator(comptime T: type) type { |
| 1964 | return struct { |
| 1965 | buffer: []const T, |
| 1966 | index: ?usize, |
| 1967 | delimiter: []const T, |
| 1968 | |
| 1969 | const Self = @This(); |
| 1970 | |
| 1971 | /// Returns a slice of the next field, or null if splitting is complete. |
| 1972 | pub fn next(self: *Self) ?[]const T { |
| 1973 | const end = self.index orelse return null; |
| 1974 | const start = if (lastIndexOf(T, self.buffer[0..end], self.delimiter)) |delim_start| blk: { |
| 1975 | self.index = delim_start; |
| 1976 | break :blk delim_start + self.delimiter.len; |
| 1977 | } else blk: { |
| 1978 | self.index = null; |
| 1979 | break :blk 0; |
| 1980 | }; |
| 1981 | return self.buffer[start..end]; |
| 1982 | } |
| 1983 | |
| 1984 | /// Returns a slice of the remaining bytes. Does not affect iterator state. |
| 1985 | pub fn rest(self: Self) []const T { |
| 1986 | const end = self.index orelse 0; |
| 1987 | return self.buffer[0..end]; |
| 1988 | } |
| 1989 | }; |
| 1990 | } |
| 1991 | |
| 1865 | 1992 | /// Naively combines a series of slices with a separator. |
| 1866 | 1993 | /// Allocates memory for the result, which must be freed by the caller. |
| 1867 | 1994 | pub fn join(allocator: Allocator, separator: []const u8, slices: []const []const u8) ![]u8 { |