Skip to content

Commit

Permalink
Arg. to avoid escaping backslahes (escape_string) (JuliaLang#38597)
Browse files Browse the repository at this point in the history
* Arg. to avoid escaping backslahes (escape_string)

This commit adds an argument to `escape_string` to assume that all
backslashes (`\\`) are already escaped. Hence, `\\cdot` becomes `\\cdot`
instead of `\\\\cdot`.

The default value to this argument is `false`. Hence, this does not
break any existing code since `escape_string` behaves exactly the same
as before if no additional option is passed.

Closes JuliaLang#34042

* Replace `bsescaped` arg. with `keep` keyword

* Update NEWS.md

* Fix doc tests

* Add compat annotation

Co-authored-by: Ronan Arraes Jardim Chagas <[email protected]>
  • Loading branch information
2 people authored and ElOceanografo committed May 4, 2021
1 parent 63aa110 commit ab2990b
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 4 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Julia v1.7 Release Notes
New language features
---------------------
* `count` and `findall` now accept an `AbstractChar` argument to search for a character in a string ([#38675]).
* `escape_string` can now receive a collection of characters in the keyword
`keep` that are to be kept as they are. ([#38597])

Language changes
----------------
Expand Down
20 changes: 16 additions & 4 deletions base/strings/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,8 @@ escape_nul(c::Union{Nothing, AbstractChar}) =
(c !== nothing && '0' <= c <= '7') ? "\\x00" : "\\0"

"""
escape_string(str::AbstractString[, esc])::AbstractString
escape_string(io, str::AbstractString[, esc::])::Nothing
escape_string(str::AbstractString[, esc]; keep = ())::AbstractString
escape_string(io, str::AbstractString[, esc]; keep = ())::Nothing
General escaping of traditional C and Unicode escape sequences. The first form returns the
escaped string, the second prints the result to `io`.
Expand All @@ -323,11 +323,20 @@ unambiguous), unicode code point (`"\\u"` prefix) or hex (`"\\x"` prefix).
The optional `esc` argument specifies any additional characters that should also be
escaped by a prepending backslash (`\"` is also escaped by default in the first form).
The argument `keep` specifies a collection of characters which are to be kept as
they are. Notice that `esc` has precedence here.
!!! compat "Julia 1.7"
The `keep` argument is available as of Julia 1.7.
# Examples
```jldoctest
julia> escape_string("aaa\\nbbb")
"aaa\\\\nbbb"
julia> escape_string("aaa\\nbbb"; keep = '\\n')
"aaa\\nbbb"
julia> escape_string("\\xfe\\xff") # invalid utf-8
"\\\\xfe\\\\xff"
Expand All @@ -341,11 +350,13 @@ julia> escape_string(string('\\u2135','\\0','0')) # \\0 would be ambiguous
## See also
[`unescape_string`](@ref) for the reverse operation.
"""
function escape_string(io::IO, s::AbstractString, esc="")
function escape_string(io::IO, s::AbstractString, esc=""; keep = ())
a = Iterators.Stateful(s)
for c::AbstractChar in a
if c in esc
print(io, '\\', c)
elseif c in keep
print(io, c)
elseif isascii(c)
c == '\0' ? print(io, escape_nul(peek(a)::Union{AbstractChar,Nothing})) :
c == '\e' ? print(io, "\\e") :
Expand All @@ -368,7 +379,8 @@ function escape_string(io::IO, s::AbstractString, esc="")
end
end

escape_string(s::AbstractString, esc=('\"',)) = sprint(escape_string, s, esc, sizehint=lastindex(s))
escape_string(s::AbstractString, esc=('\"',); keep = ()) =
sprint((io)->escape_string(io, s, esc; keep = keep), sizehint=lastindex(s))

function print_quoted(io, s::AbstractString)
print(io, '"')
Expand Down
7 changes: 7 additions & 0 deletions test/strings/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@
@test typeof(escape_string("test", "t")) == String
@test escape_string("test", "t") == "\\tes\\t"

@test escape_string("\\cdot") == "\\\\cdot"
@test escape_string("\\cdot"; keep = '\\') == "\\cdot"
@test escape_string("\\cdot", '\\'; keep = '\\') == "\\\\cdot"
@test escape_string("\\cdot\n"; keep = "\\\n") == "\\cdot\n"
@test escape_string("\\cdot\n", '\n'; keep = "\\\n") == "\\cdot\\\n"
@test escape_string("\\cdot\n", "\\\n"; keep = "\\\n") == "\\\\cdot\\\n"

for i = 1:size(cx,1)
cp, ch, st = cx[i,:]
@test cp == convert(UInt32, ch)
Expand Down

0 comments on commit ab2990b

Please sign in to comment.