Reputation: 19963
Summary
Can you use a regular expression to match multiple characters, but replace individual characters with specific replacements.
For instance, replace \
with \\
and replace "
with \x22
and replace '
with \x27
.
It is my understanding that this is simply not possible, as you can use the captured sub-matches within the expression, but not with any level of logic that would allow you to conditionally output text if a sub-match took place.
The following VB.NET code is obviously totally incorrect, but gives you an idea of my thinking... (i.e. if there was a replacement command that allowed you to say "if sub-match 1 happened, then output \\
instead")
RegEx.Replace(text, "(\)?("")?(')?", "{if($1,'\\')}{if($2,'\x22')}{if($2,'\x27')}")
(This would be for use with .NET RegEx class, but would be useful for use with javascript RegExp class)
Background
More for interest than actual need, but I've been playing with encoding text for use within javascript parameters. (Well, the need is certainly there, but the interest is efficiency.)
I've been using the standard String.Replace
, and doing some tests for performance with the following two functions...
Public Function GetJSSafeString(ByVal text As String) As String
Return text.Replace("\", "\\").Replace("""", "\x22").Replace("'", "\x27")
End Function
Public Function GetJSSafeString2(ByVal text As String) As String
If text.Contains("\") Then
text = text.Replace("\", "\\")
End If
If text.Contains("""") Then
text = text.Replace("""", "\x22")
End If
If text.Contains("'") Then
text = text.Replace("'", "\x27")
End If
Return text
End Function
Using two strings, both around 200 characters in length - the first does not contain any characters to be converted - the second contains one of each character to be converted (\"'
). I ran each of the two strings through the two functions 100000 times each.
The four results are coming out (in total-milliseconds) roughly as...
GetJSSafeString, no converted characters: 182.0364
GetJSSafeString, converted characters: 316.0632
GetJSSafeString2, no converted characters: 60.012
GetJSSafeString2, converted characters: 354.0708
So obviously GetJSSafeString2 is best if there are no replacement, and worst if there are characters to convert (but not much worse, so looks like the better choice).
But it got me thinking... could this be done with a single regular expression?
And if so, would it be faster than either of the two above functions?
Upvotes: 2
Views: 1438
Reputation: 19963
Big thanks to @psxls for his answer, which will be useful for future javascript implementation.
His answer made me look at the overloads for the .NET RegEx.Replace function (which to be honest, I should have done in the first place, my bad)... and there is a MatchEvaluator delegate.
So I have implemented the following code as a test (to compliment the code already in my answer)...
Public Function GetJSSafeString3(ByVal text As String) As String
Return Regex.Replace(text, "(\\|""|')", New MatchEvaluator(AddressOf GetJSSafeString3Eval))
End Function
Public Function GetJSSafeString3Eval(ByVal textMatch As Match) As String
Select Case textMatch.Value
Case "\"
Return "\\"
Case """"
Return "\x22"
Case "'"
Return "\x27"
End Select
Return ""
End Function
And the results are as I expected... that this is far, far less efficient than either of the functions in my original question function. (The following are in milliseconds)
GetJSSafeString, no converted characters: 182
GetJSSafeString, converted characters: 316
GetJSSafeString2, no converted characters: 60
GetJSSafeString2, converted characters: 354
GetJSSafeString3, no converted characters: 477
GetJSSafeString3, converted characters: 856
As the majority of the strings that I will be converting will not contain any of the characters mentioned, I am implementing the GetJSSafeString*2* function, as that is by far the most efficient for the majority of situations.
Upvotes: 1
Reputation: 6935
The solution in JavaScript:
var text="this is a test \\ with \"things\" to ' replace";
var h={'\\':'\\\\', '"':"\\x22", "'":"\\x27"}; //we define here the replacements
text=text.replace(/("|\\|')/g,function(match){return h[match]});
alert(text); //prints: this is a test \\ with \x22things\x22 to \x27 replace
Upvotes: 2