Trouver et supprimer des caractères non ascii d'un oracle Varchar2

nous sommes en train de migrer une de nos bases de données oracle vers UTF8 et nous avons trouvé quelques enregistrements qui sont proches de la limite de 4000 octets de varchar. Lorsque nous essayons de migrer ces enregistrements, ils échouent car ils contiennent des caractères qui deviennent des caractères UF8 multibytes. Ce que je veux faire avec PL/SQL, c'est localiser ces caractères pour voir ce qu'ils sont et les modifier ou les supprimer.

je voudrais faire :

SELECT REGEXP_REPLACE(COLUMN,'[^[:ascii:]],'')

Oracle n'implémente pas le [: ascii:] classe de personnage.

Est-il un moyen simple de faire ce que je veux faire?

21
demandé sur FerranB 2010-02-10 14:42:10

16 réponses

dans un codage ASCII compatible avec un seul octet (par exemple Latin-1), les caractères ASCII sont simplement des octets compris entre 0 et 127. Donc vous pouvez utiliser quelque chose comme [\x80-\xFF] pour détecter les caractères non ASCII.

6
répondu Max Shawabkeh 2010-02-10 11:44:21

Si vous utilisez le ASCIISTR fonction pour convertir L'Unicode en littérales de la forme \nnnn, vous pouvez utiliser REGEXP_REPLACE pour enlever ces littérales, comme ça...

UPDATE table SET field = REGEXP_REPLACE(ASCIISTR(field), '\[[:xdigit:]]{4}', '')

...où le champ et la table sont respectivement vos noms de champ et de table.

22
répondu Robb Smith 2012-02-10 08:03:56

je pense que cela fera l'affaire:

SELECT REGEXP_REPLACE(COLUMN, '[^[:print:]]', '')
14
répondu Yuri Tkachenko 2016-06-21 12:03:10

je ne le recommande pas pour la production de code, mais il a un sens et semble fonctionner:

SELECT REGEXP_REPLACE(COLUMN,'[^' || CHR(1) || '-' || CHR(127) || '],'')
9
répondu Francisco Hayoz 2013-08-14 14:34:37

il y a probablement un moyen plus direct d'utiliser des expressions régulières. Avec un peu de chance, quelqu'un d'autre. Mais voilà ce que je ferais sans avoir à consulter les manuels.

créer une fonction PLSQL pour recevoir votre chaîne de caractères et retourner un varchar2.

dans la fonction PLSQL, faites un asciistr () de votre entrée. Le PLSQL est parce que cela peut retourner une chaîne plus longue que 4000 et vous avez 32K disponibles pour varchar2 en PLSQL.

Cette fonction convertit le caractères non-ASCII à la notation \xxxx. Vous pouvez donc utiliser des expressions régulières pour les trouver et les supprimer. Puis retourner le résultat.

3
répondu Jim Hudson 2010-02-10 14:15:31

La suite fonctionne aussi:

select dump(a,1016), a from (
SELECT REGEXP_REPLACE (
          CONVERT (
             '3735844533120%  ',
             'US7ASCII',
             'WE8ISO8859P1'),
          '[^!@/\.,;:<>#$%&()_=[:alnum:][:blank:]]') a
  FROM DUAL);
3
répondu Sajid 2012-02-10 08:04:18

Le select peut ressembler à l'exemple suivant:

select nvalue from table
where length(asciistr(nvalue))!=length(nvalue)  
order by nvalue;
3
répondu Jeff Dwight 2012-12-12 20:20:21

j'ai eu un problème similaire et blogué à ce sujet ici. J'ai commencé avec l'expression régulière pour Alpha numerics, puis j'ai ajouté quelques caractères de ponctuation de base que j'aimais:

select dump(a,1016), a, b
from
 (select regexp_replace(COLUMN,'[[:alnum:]/''%()> -.:=;[]','') a,
         COLUMN b
  from TABLE)
where a is not null
order by a;

j'ai utilisé dump avec la variante 1016 pour donner les caractères hexadécimaux que je voulais remplacer et que je pouvais ensuite utiliser dans un utl_raw.cast_to_varchar2.

2
répondu Gary Myers 2010-02-10 22:29:01

j'ai trouvé la réponse ici:

http://www.squaredba.com/remove-non-ascii-characters-from-a-column-255.html

CREATE OR REPLACE FUNCTION O1DW.RECTIFY_NON_ASCII(INPUT_STR IN VARCHAR2)
RETURN VARCHAR2
IS
str VARCHAR2(2000);
act number :=0;
cnt number :=0;
askey number :=0;
OUTPUT_STR VARCHAR2(2000);
begin
str:=’^'||TO_CHAR(INPUT_STR)||’^';
cnt:=length(str);
for i in 1 .. cnt loop
askey :=0;
select ascii(substr(str,i,1)) into askey
from dual;
if askey < 32 or askey >=127 then
str :=’^'||REPLACE(str, CHR(askey),”);
end if;
end loop;
OUTPUT_STR := trim(ltrim(rtrim(trim(str),’^'),’^'));
RETURN (OUTPUT_STR);
end;
/

puis exécutez ceci pour mettre à jour vos données

update o1dw.rate_ipselect_p_20110505
set NCANI = RECTIFY_NON_ASCII(NCANI);
2
répondu Matt McGurie 2011-08-09 20:47:08

Essayez le code suivant:

-- To detect
select 1 from dual
where regexp_like(trim('xx test text æ¸¬è© ¦ “xmx” number²'),'['||chr(128)||'-'||chr(255)||']','in')

-- To strip out
select regexp_replace(trim('xx test text æ¸¬è© ¦ “xmxmx” number²'),'['||chr(128)||'-'||chr(255)||']','',1,0,'in')
from dual
2
répondu Kok-Yan Lo 2012-04-24 03:03:24

réponse donnée par Francisco Hayoz est la meilleure. N'utilisez pas les fonctions pl/sql si sql peut le faire pour vous.

voici le test simple dans Oracle 11.2.03

select s
     , regexp_replace(s,'[^'||chr(1)||'-'||chr(127)||']','') "rep ^1-127"
     , dump(regexp_replace(s,'['||chr(127)||'-'||chr(225)||']','')) "rep 127-255"
from (
select listagg(c, '') within group (order by c) s
  from (select 127+level l,chr(127+level) c from dual connect by level < 129))

et "rep 127-255" est

Typ=1 Len=30: 226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255

I. e pour une raison quelconque, cette version D'Oracle ne remplace pas char(226) et au-dessus. Utiliser '['||chr(127)||'-'||chr(225)||']' donne le résultat souhaité. Si vous avez besoin de remplacer d'autres caractères, Ajoutez-les au regex ci-dessus ou utilisez replace|regexp_replace imbriqué si le remplacement est différent alors " (chaîne null).

0
répondu Alex S 2014-04-23 00:32:53

Merci, cela a fonctionné pour mes fins. BTW il manque une citation dans l'exemple ci-dessus.

REGEXP_REPLACE (COLUMN, ' [^'//CHR (32) || '-' || CHR (127) || ']', ' '))

Je l'ai utilisé dans une fonction word-wrap. De temps en temps, il y avait un NewLine/ NL / CHR(10) / 0A dans le texte entrant qui gâchait tout.

0
répondu allen 2014-08-29 20:25:13

Veuillez noter que lorsque vous utilisez

regexp_like(column, '[A-Z]')

le moteur de regexp D'Oracle va correspondre à certains caractères de la gamme Latin-1 aussi bien: ceci s'applique à tous les caractères qui ressemblent à des caractères ASCII comme Ä->A, Ö->O, Ü - >U, etc., de sorte que [A-Z] n'est pas ce que vous savez d'autres environnements comme, disons, Perl.

au lieu de jouer avec des expressions régulières essayez de changer pour le type de données NVARCHAR2 avant la mise à jour des jeux de caractères.

une Autre approche: au lieu de couper une partie du contenu des champs, vous pouvez essayer la fonction SOUNDEX, à condition que votre base de données ne contienne que des caractères européens (par exemple, Latin-1). Ou vous écrivez juste une fonction qui traduit des caractères de la gamme Latin-1 en caractères ASCII similaires, comme

  • å =>
  • ä =>
  • ö = > o

bien sûr que pour les blocs de texte dépassant 4000 octets lorsqu'il est transformé en UTF-8.

0
répondu elwood 2015-10-31 21:51:05

Vous pouvez essayer quelque chose comme ceci pour rechercher la colonne contenant le caractère non-ascii :

select * from your_table where your_col <> asciistr(your_col);
0
répondu Shardul Dhanorkar 2016-11-22 10:55:28

ce Faire, il faudra travailler.

trim(replace(ntwk_slctor_key_txt, chr(0), ''))
-2
répondu Mohan 2015-08-04 22:31:34

je suis un peu en retard pour répondre à cette question, mais j'ai eu le même problème récemment (les gens coupent et collent toutes sortes de choses dans une chaîne et nous ne savons pas toujours ce que c'est). Ce qui suit est un simple caractère de la liste blanche de l'approche:

SELECT est.clients_ref
  ,TRANSLATE (
              est.clients_ref
             ,   'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890#$%^&*()_+-={}|[]:";<>?,./'
              || REPLACE (
                          TRANSLATE (
                                     est.clients_ref
                                    ,'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890#$%^&*()_+-={}|[]:";<>?,./'
                                    ,'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
                                    )
                         ,'~'
                         )
             ,'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890#$%^&*()_+-={}|[]:";<>?,./'
             )
      clean_ref

à PARTIR de edms_staging_table hne

-3
répondu user5531447 2015-11-06 08:25:21