diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index f4bbffe2..91c55276 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -227,6 +227,10 @@ template OutputIt write_delimiter(OutputIt out) { return out; } +template inline bool is_printable_ascii(Char c) { + return c >= 0x20 && c < 0x7e; +} + template < typename Char, typename OutputIt, typename Arg, FMT_ENABLE_IF(is_std_string_like::type>::value)> @@ -247,8 +251,14 @@ OutputIt write_range_entry(OutputIt out, const Arg& v) { c = 't'; break; case '"': + FMT_FALLTHROUGH; + case '\\': *out++ = '\\'; break; + default: + if (is_printable_ascii(c)) break; + out = format_to(out, "\\x{:02x}", c); + continue; } *out++ = c; } diff --git a/test/ranges-test.cc b/test/ranges-test.cc index f3fc9df1..21924cb9 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -264,6 +264,7 @@ TEST(ranges_test, join_range) { #endif // FMT_RANGES_TEST_ENABLE_JOIN TEST(ranges_test, escape_string) { - auto v = std::vector{"\n\r\t\""}; - EXPECT_EQ(fmt::format("{}", v), "[\"\\n\\r\\t\\\"\"]"); + EXPECT_EQ(fmt::format("{}", std::vector{"\n\r\t\"\\"}), + "[\"\\n\\r\\t\\\"\\\\\"]"); + EXPECT_EQ(fmt::format("{}", std::vector{"\x7"}), "[\"\\x07\"]"); } \ No newline at end of file