| ... | @@ -1876,7 +1876,11 @@ test "rotate" { | ... | @@ -1876,7 +1876,11 @@ test "rotate" { |
| 1876 | | 1876 | |
| 1877 | /// Replace needle with replacement as many times as possible, writing to an output buffer which is assumed to be of | 1877 | /// Replace needle with replacement as many times as possible, writing to an output buffer which is assumed to be of |
| 1878 | /// appropriate size. Use replacementSize to calculate an appropriate buffer size. | 1878 | /// appropriate size. Use replacementSize to calculate an appropriate buffer size. |
| | 1879 | /// The needle must not be empty. |
| 1879 | pub fn replace(comptime T: type, input: []const T, needle: []const T, replacement: []const T, output: []T) usize { | 1880 | pub fn replace(comptime T: type, input: []const T, needle: []const T, replacement: []const T, output: []T) usize { |
| | 1881 | // Empty needle will loop until output buffer overflows. |
| | 1882 | assert(needle.len > 0); |
| | 1883 | |
| 1880 | var i: usize = 0; | 1884 | var i: usize = 0; |
| 1881 | var slide: usize = 0; | 1885 | var slide: usize = 0; |
| 1882 | var replacements: usize = 0; | 1886 | var replacements: usize = 0; |
| ... | @@ -1899,22 +1903,48 @@ pub fn replace(comptime T: type, input: []const T, needle: []const T, replacemen | ... | @@ -1899,22 +1903,48 @@ pub fn replace(comptime T: type, input: []const T, needle: []const T, replacemen |
| 1899 | test "replace" { | 1903 | test "replace" { |
| 1900 | var output: [29]u8 = undefined; | 1904 | var output: [29]u8 = undefined; |
| 1901 | var replacements = replace(u8, "All your base are belong to us", "base", "Zig", output[0..]); | 1905 | var replacements = replace(u8, "All your base are belong to us", "base", "Zig", output[0..]); |
| | 1906 | var expected: []const u8 = "All your Zig are belong to us"; |
| 1902 | testing.expect(replacements == 1); | 1907 | testing.expect(replacements == 1); |
| 1903 | testing.expect(eql(u8, output[0..], "All your Zig are belong to us")); | 1908 | testing.expectEqualStrings(expected, output[0..expected.len]); |
| 1904 | | 1909 | |
| 1905 | replacements = replace(u8, "Favor reading code over writing code.", "code", "", output[0..]); | 1910 | replacements = replace(u8, "Favor reading code over writing code.", "code", "", output[0..]); |
| | 1911 | expected = "Favor reading over writing ."; |
| 1906 | testing.expect(replacements == 2); | 1912 | testing.expect(replacements == 2); |
| 1907 | testing.expect(eql(u8, output[0..], "Favor reading over writing .")); | 1913 | testing.expectEqualStrings(expected, output[0..expected.len]); |
| | 1914 | |
| | 1915 | // Empty needle is not allowed but input may be empty. |
| | 1916 | replacements = replace(u8, "", "x", "y", output[0..0]); |
| | 1917 | expected = ""; |
| | 1918 | testing.expect(replacements == 0); |
| | 1919 | testing.expectEqualStrings(expected, output[0..expected.len]); |
| | 1920 | |
| | 1921 | // Adjacent replacements. |
| | 1922 | |
| | 1923 | replacements = replace(u8, "\\n\\n", "\\n", "\n", output[0..]); |
| | 1924 | expected = "\n\n"; |
| | 1925 | testing.expect(replacements == 2); |
| | 1926 | testing.expectEqualStrings(expected, output[0..expected.len]); |
| | 1927 | |
| | 1928 | replacements = replace(u8, "abbba", "b", "cd", output[0..]); |
| | 1929 | expected = "acdcdcda"; |
| | 1930 | testing.expect(replacements == 3); |
| | 1931 | testing.expectEqualStrings(expected, output[0..expected.len]); |
| 1908 | } | 1932 | } |
| 1909 | | 1933 | |
| 1910 | /// Calculate the size needed in an output buffer to perform a replacement. | 1934 | /// Calculate the size needed in an output buffer to perform a replacement. |
| | 1935 | /// The needle must not be empty. |
| 1911 | pub fn replacementSize(comptime T: type, input: []const T, needle: []const T, replacement: []const T) usize { | 1936 | pub fn replacementSize(comptime T: type, input: []const T, needle: []const T, replacement: []const T) usize { |
| | 1937 | // Empty needle will loop forever. |
| | 1938 | assert(needle.len > 0); |
| | 1939 | |
| 1912 | var i: usize = 0; | 1940 | var i: usize = 0; |
| 1913 | var size: usize = input.len; | 1941 | var size: usize = input.len; |
| 1914 | while (i < input.len) : (i += 1) { | 1942 | while (i < input.len) { |
| 1915 | if (mem.indexOf(T, input[i..], needle) == @as(usize, 0)) { | 1943 | if (mem.indexOf(T, input[i..], needle) == @as(usize, 0)) { |
| 1916 | size = size - needle.len + replacement.len; | 1944 | size = size - needle.len + replacement.len; |
| 1917 | i += needle.len; | 1945 | i += needle.len; |
| | 1946 | } else { |
| | 1947 | i += 1; |
| 1918 | } | 1948 | } |
| 1919 | } | 1949 | } |
| 1920 | | 1950 | |
| ... | @@ -1923,9 +1953,15 @@ pub fn replacementSize(comptime T: type, input: []const T, needle: []const T, re | ... | @@ -1923,9 +1953,15 @@ pub fn replacementSize(comptime T: type, input: []const T, needle: []const T, re |
| 1923 | | 1953 | |
| 1924 | test "replacementSize" { | 1954 | test "replacementSize" { |
| 1925 | testing.expect(replacementSize(u8, "All your base are belong to us", "base", "Zig") == 29); | 1955 | testing.expect(replacementSize(u8, "All your base are belong to us", "base", "Zig") == 29); |
| 1926 | testing.expect(replacementSize(u8, "", "", "") == 0); | | |
| 1927 | testing.expect(replacementSize(u8, "Favor reading code over writing code.", "code", "") == 29); | 1956 | testing.expect(replacementSize(u8, "Favor reading code over writing code.", "code", "") == 29); |
| 1928 | testing.expect(replacementSize(u8, "Only one obvious way to do things.", "things.", "things in Zig.") == 41); | 1957 | testing.expect(replacementSize(u8, "Only one obvious way to do things.", "things.", "things in Zig.") == 41); |
| | 1958 | |
| | 1959 | // Empty needle is not allowed but input may be empty. |
| | 1960 | testing.expect(replacementSize(u8, "", "x", "y") == 0); |
| | 1961 | |
| | 1962 | // Adjacent replacements. |
| | 1963 | testing.expect(replacementSize(u8, "\\n\\n", "\\n", "\n") == 2); |
| | 1964 | testing.expect(replacementSize(u8, "abbba", "b", "cd") == 8); |
| 1929 | } | 1965 | } |
| 1930 | | 1966 | |
| 1931 | /// Perform a replacement on an allocated buffer of pre-determined size. Caller must free returned memory. | 1967 | /// Perform a replacement on an allocated buffer of pre-determined size. Caller must free returned memory. |