3

Let say I have an input string like this: HÊLLÕ WÖRLЩ !!

I also have a table namely REPLACE_CHAR_TAB which have a data as below:

SPECIAL_ASCII     SPECIAL_CHAR     REPLACE_ASCII     REPLACE_CHAR
-----------------------------------------------------------------
          169                ©              NULL             NULL
          202                Ê                69                E
          208                Ð                68                D
          213                Õ                79                O

Now, I wanted to validate the input string with the data in this table, and whenever the special character in the string is found in this table, the input string character will be replace by REPLACE_CHAR in this table.

Example:

Input: HÊLLÕ WÖRLЩ !!
Output: HELLO WORLD !!

I am new to PL/SQL, can I have some help and hints on how I can achieve this please?

Appreciate on the guidance and help! Thanks!

1

3 Answers 3

2

You can use Oracle ASCII function to calculate the ASCII value of each character of your string, but your design is a little bit dangerous for your performance.

Instead, I recomend you use TRANSLATE. Take a look:

SELECT TRANSLATE('HÊLLÕ WÖRLЩ', '©ÊÐÖÕ', ' EDOO') 
FROM DUAL;

Good luck!

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the guidance. However, it is required for me to go through the table dictionary (replace_char_tab) for my requirement. Besides, there is actually something like special_char: æ, replace_char: ae. In this case, the replace_char is actually 2 characters which I think TRANSLATE won't able to produce accurate results?
1

Tried to come up with a solution which will match your exact requirement: Given a table with special character and corresponding normal character mapping we need to write a PL/SQL to get the mappings done.

  1. Create table with mappings
create table replace_char_tab(special_ascii number, special_char nvarchar2(1), 
                              replace_ascii number, replace_char varchar2(1));
insert into replace_char_tab values(49833,'©', null, null);
insert into replace_char_tab values(50058,'Ê', 69, 'E');
insert into replace_char_tab values(50064,'Ð', 68, 'D');
insert into replace_char_tab values(50070,'Ö', 79, 'O');
insert into replace_char_tab values(50069,'Õ', 79, 'O');
commit;

In the above statements we have bigger values for special_ascii, because Oracle's ascii supports 0-127 characters natively. For a higher range the unicode value is returned based on the character encoding of the database.

  1. Create a PL/SQL
create or replace function getSpecialCharMapping(input_string varchar2)
return varchar2
as
     TYPE key_pair_type IS TABLE OF number INDEX BY pls_integer;
     special_rep key_pair_type;
     output_string varchar2(4000);
     r_char nvarchar2(1);
begin
   -- Generate associative array
   for rec in (select * from replace_char_tab) loop
      if rec.replace_ascii is not null then
         special_rep(rec.special_ascii) := rec.replace_ascii;
      else
         special_rep(rec.special_ascii) := 0;
      end if;
   end loop;
   -- Now find map the special chars with ascii
   for cnt in 1..length(input_string) loop
      if special_rep.exists(ascii(substr(input_string, cnt, 1))) then
            output_string := output_string 
            || chr(special_rep(ascii(substr(input_string,cnt,1))));
      else
         output_string := output_string || substr(input_string,cnt,1);
      end if;
    end loop;
    return output_string;
end;
/

In the above PL/SQL we have used associative array feature of PL/SQL. Which essentially is a key/value pair and helps in fast lookup. By using associative array we are trying to avoid querying table for each character mapping.

  1. Sample execution
select getSpecialCharMapping('HÊLLÕ WÖRLЩ !!') from dual;

The motive of this solution is to make special character mapping scalable and easy to understand.

Link to SQLFiddle.

Comments

1

Oracle offers the TRANSLATE function for replacing single characters. So get the characters from your conversion table using LISTAGG and use the resulting strings for conversion:

select translate('HÊLLÕ WÖRLЩ !!', specials, replacers)
from 
(
  select 
    listagg(special_char,'') within group 
      (order by replace_ascii, special_ascii) as specials,
    listagg(replace_char,'') within group 
      (order by replace_ascii, special_ascii) as replacers
  from replace_char_tab
);

SQL fiddle: http://www.sqlfiddle.com/#!4/f4d80/1.

(It is important to sort by replace_ascii first, by the way, so you get the nulls last. Thus TRANSLATE removes the according characters. Another order would result in two strings where the positions wouldn't match.)


If you want to replace with more than one character such as æ to ae, as you say in your comment, you cannot use TRANSLATE any longer. Instead you would have to run through your translation table recursively with REPLACE and then keep the last modified string. In order to access one translation table record after the other, you must number your records first, so as to always get the next one.

with numbered as
(
  select /*+ materialize */
    replace_char_tab.*,
    row_number() over (order by replace_ascii, special_ascii) as num 
  from replace_char_tab  
)
, replaced(str, num) as
(
  select 'HÊLLÕ WÖRLЩ !!' as str, 0 as num from dual
  union all
  select
    replace(replaced.str, numbered.special_char, numbered.replace_char) as str,
    numbered.num
  from replaced 
  join numbered on numbered.num = replaced.num + 1
)
select max(str) keep (dense_rank last order by num) from replaced;

SQL fiddle: http://www.sqlfiddle.com/#!4/aa65d7/3.

2 Comments

I notice the used of LISTAGG and TRANSLATE too. However, in teh special_char_tab it contains something like the special_character: æ and its replace_character: ae. In this case the replace_character is having 2 characters and hence i think the LISTAGG and TRANSLATE solution won't be able to work.. hmm..
You are right, you cannot use TRANSLATE then. I've edited my answer to show how to iterate through your records with REPLACE instead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.