6

I have an equation stored in my table. I am fetching one equation at a time and want to replace all the operators with any other character.

Input String: (N_100-(6858)*(6858)*N_100/0_2)%N_35

Operators or patterns: (+, -, *, /, %, (, ))

Replacement character: ~

Output String: ~N_100~~6858~~~6858~~N_100~0_2~~N_35

I had tried below query with Nested REPLACE Functions and I got desired output:

DECLARE @NEWSTRING VARCHAR(100) 
SET @NEWSTRING = '(N_100-(6858)*(6858)*N_100/0_2)%N_35' ;
SELECT @NEWSTRING = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
                    @NEWSTRING, '+', '~'), '-', '~'), '*', '~'), '/', '~')
                   , '%', '~'), '(', '~'), ')', '~')
PRINT @NEWSTRING

Output: ~N_100~~6858~~~6858~~N_100~0_2~~N_35

How can I replace all the operators without using nested replace functions?

Lukasz Szozda
  • 162,964
  • 23
  • 234
  • 275
Saharsh Shah
  • 28,687
  • 8
  • 48
  • 83

5 Answers5

12

I believe it is easier and more readable if you use a table to drive this.

declare @String varchar(max) = '(N_100-(6858)*(6858)*N_100/0_2)%N_35'

--table containing values to be replaced
create table #Replace 
(
    StringToReplace varchar(100) not null primary key clustered
    ,ReplacementString varchar(100) not null    
)

insert into #Replace (StringToReplace, ReplacementString)
values ('+', '~')
    ,('-', '~')
    ,('*', '~')
    ,('/', '~')
    ,('%', '~')
    ,('(', '~')
    ,(')', '~')

select @String = replace(@String, StringToReplace, ReplacementString)
from #Replace a

select @String

drop table #Replace
Shane Gebs
  • 121
  • 1
  • 2
  • This is definitely better than using a split function (and a horribly inefficient one at that) to spit out a table dynamically. It is also 1000 times better than a while loop using a WHILE loop and PATINDEX :). +1 – Solomon Rutzky Dec 18 '14 at 16:30
  • @srutzky OR Shane Gebs, if you're out there -- I'd love to have something like this (running on a field from each row of a table variable rather than a scalar), but for some reason, it is only replacing the first pair of values (first row) of #Replace (?) ---- that is, I've got letter pairs `('a', '+a'), ('b','+b'),('c'`...etc and it's replacing all occurrences of `a` in the field of each row with `+a`, but not the `b` or `c`, etc replacements (?) – Code Jockey Feb 05 '15 at 16:20
  • 1
    @CodeJockey Create a new question, reference this answer, and show what your current code is and the data you are trying to manipulate. Then post a link to that question here and I will answer it. – Solomon Rutzky Feb 05 '15 at 16:29
  • @SolomonRutzky Hey ! I am trying to do exactly what CodeJockey asked for. Would you mind take a look at this question? https://stackoverflow.com/questions/45800289 – Ayorus Aug 21 '17 at 18:00
5

There is not equivalent for the TRANSLATE function from Oracle in SQL Server, you have to use nested replace functions.

The following solution is technically correct:

DECLARE @newstring VARCHAR(100) = '(N_100-(6858)*(6858)*N_100/0_2)%N_35';
DECLARE @pattern VARCHAR(100) = '%[+-\*/%()]%';
DECLARE @i INT;
BEGIN
  SET @i = PATINDEX(@pattern,@newstring) 
  WHILE @i <> 0
  BEGIN
    SET @newstring = LEFT(@newstring,@i-1) + '~' + SUBSTRING(@newstring,@i+1,100);
    SET @i = PATINDEX(@pattern,@newstring) 
  END
  SELECT @newstring;
END;

But I do not see why you would favor this over nested REPLACE calls.

Twinkles
  • 1,984
  • 1
  • 17
  • 31
1

The easiest way is to use TRANSLATE function. It is availble from SQL Server 2017 (aka vNext) and above.

TRANSLATE

Returns the string provided as a first argument after some characters specified in the second argument are translated into a destination set of characters.

TRANSLATE ( inputString, characters, translations) 

Returns a character expression of the same type as inputString where characters from the second argument are replaced with the matching characters from third argument.

In your case:

SELECT TRANSLATE('(N_100-(6858)*(6858)*N_100/0_2)%N_35', '+-*/%()','~~~~~~~')

DBFiddle Demo

Lukasz Szozda
  • 162,964
  • 23
  • 234
  • 275
0

I had created a SPLIT function to implement this because I need to implement this operation multiple time in PROCEDURE

SPLIT FUNCTION

create function [dbo].[Split](@String varchar(8000), @Delimiter char(1))       
returns @temptable TABLE (items varchar(8000))       
as       
begin       
    declare @idx int       
    declare @slice varchar(8000)       

    select @idx = 1       
        if len(@String)<1 or @String is null  return       

    while @idx!= 0       
    begin       
        set @idx = charindex(@Delimiter,@String)       
        if @idx!=0       
            set @slice = left(@String,@idx - 1)       
        else       
            set @slice = @String       

        if(len(@slice)>0)  
            insert into @temptable(Items) values(@slice)       

        set @String = right(@String,len(@String) - @idx)       
        if len(@String) = 0 break       
    end   
return       
end

Code used in procedure:

DECLARE @NEWSTRING VARCHAR(100) 
SET @NEWSTRING = '(N_100-(6858)*(6858)*N_100/0_2)%N_35' ;
SELECT @NEWSTRING = REPLACE(@NEWSTRING, items, '~') FROM dbo.Split('+,-,*,/,%,(,)', ',');
PRINT @NEWSTRING

OUTPUT

~N_100~~6858~~~6858~~N_100~0_2~~N_35
Saharsh Shah
  • 28,687
  • 8
  • 48
  • 83
  • This is no need for a split function. The only purpose it is serving is to dynamically spit out a table. Since the replacement characters are a small, finite set, it is much much better to just create a temp table as shown in @Shane's answer. Also, there are many ways to accomplish a string split in T-SQL, and you have chosen the slowest. Please look into a SQLCLR-based splitter (you can get for free via [SQL#](http://www.SQLsharp.com) (which I am the creator of but String_Split is in the Free version) or, at the very least, an XML-based splitter. – Solomon Rutzky Dec 18 '14 at 16:33
  • @srutzky Thank for your comment but I have to apply some business login on splitted values so I had used SPLIT function to split the values. So every time I can't use temporary table. – Saharsh Shah Dec 19 '14 at 05:46
  • Ok about using split vs temp table. But, I am also saying to not use _that_ split function. Split functions based on WHILE loops are horribly inefficient. There are several better choices. – Solomon Rutzky Dec 19 '14 at 06:21
  • @srutzky Can you provide me the other way to write split function – Saharsh Shah Dec 19 '14 at 06:25
  • I provided a link in my first comment to a free SQLCLR splitter. Or you can search the web for examples if you want to write your own. – Solomon Rutzky Dec 19 '14 at 06:29
0

you can replace all the operators without using nested replace functions

DECLARE @Pattern VARCHAR(300) ='%[+-\*/%()]%';
DECLARE @String VARCHAR(300) ='(N_100-(6858)*(6858)*N_100/0_2)%N_35';
WHILE PatIndex(@Pattern, @String) <> 0
    SELECT @String=Replace(@String, Substring(@String, PatIndex(@Pattern, @String), 1), '~')
SELECT @String 
Tsahi Asher
  • 1,767
  • 15
  • 28