2017-08-09 2 views
1

J'ai une table de titres de livres - la plupart d'entre eux sont dupliqués plusieurs fois pour différentes éditions. De nombreux titres ont été importés par erreur avec des caractères non-ASCII manquants, par exemple "La métamorphose" transformée en "La m? Tamorphose" parfois le é transformé en espace ou simplement retiré de la chaîne.Comment trouver des copies de chaîne où l'on a dépouillé des caractères non-ASCII

Le tableau

editionid | bookid | title 
-------------------------------------------- 
1   | 1  | Elementarne čestice 
2   | 1  | Elementarne ?estice 
3   | 1  | Elementarne estice 
4   | 1  | Las partículas elementales 
5   | 2  | Schöne neue Welt 
6   | 2  | Sch ne neue Welt 

Je veux identifier les titres incorrects en dépouillant la non-ASCIIs des titres et en comparant à d'autres titres du même livre. S'il y a un match, j'ai trouvé un titre défectueux.

Résultat:

o.title (flawed) | e.title (good) 
----------------------------------- 
Elementarne ?estice | Elementarne čestice 
Elementarne estice | Elementarne čestice 
Sch ne neue Welt | Schöne neue Welt 

La table est assez grande, mais puisque je ne dois faire une fois les performances ne sont pas la clé.

Mon approche:

select distinct on (o.editionid) o.title, e.title 
from editions o 
inner join editions e on (o.bookid = e.bookid) 
where o.bookid between 1 and 1000 
    and e.title !~ '^[ -~]*$' -- only for performance 
    and ((
     e.title like '%Þ%' and (o.title = regexp_replace(e.title, '[Þ]', '?') or o.title = regexp_replace(e.title, '[Þ]', ' ') or o.title = regexp_replace(e.title, '[Þ]', '')) 
    ) or (
     e.title like '%ß%' and (o.title = regexp_replace(e.title, '[ß]', '?') or o.title = regexp_replace(e.title, '[ß]', ' ') or o.title = regexp_replace(e.title, '[ß]', '')) 
    ) or (
     e.title like '%à%' and (o.title = regexp_replace(e.title, '[à]', '?') or o.title = regexp_replace(e.title, '[à]', ' ') or o.title = regexp_replace(e.title, '[à]', '')) 
    . 
    . 
    . 
    )) 

qui fonctionne jusqu'à présent, mais il semble impossible d'ajouter tous les caractères non-ASCII séparément. Quelqu'un at-il une idée d'une approche plus générale qui couvre tous les caractères non-ASCII à la fois? Deuxièmement, cela ne fonctionne pas si deux caractères différents ont été supprimés et que je ne sais pas comment résoudre ce problème.

Troisième mais peut-être impossible - souvent, certains non-ASCII ont été tournés, mais pas tous "Weiße Nächte" transformés en "Wei e Nächte" - ce serait génial si ceux-ci pouvaient être couverts.

+1

https://www.postgresql.org/docs/current/static/fuzzystrmatch.html Vous voulez probablement le concept de "distance d'édition" comme décrit ci-dessus. –

+0

Ce serait assez sujet à erreur car il ne peut pas distinguer entre ASCII ou non. – fisch

+0

c'est-à-dire 'exämple' par rapport à 'ex? Mple' ont la même distance comme 'exemple' vs 'exemple' où les deux derniers peuvent être totalement légitimes dans des lenguages ​​différents. – fisch

Répondre

0

Après quelques tripoter il n'a pas été si difficile à la fin:

select distinct on (o.editionid) o.title as flawed, e.title as good 
from editions o 
inner join editions e on (o.bookid = e.bookid) 
where o.bookid between 0 and 10000 
    and e.title ~ '[^\x00-\x7F]' 
    and (
      o.title = regexp_replace(e.title, '[^\x00-\x7F]', '?', 'g') 
      or o.title = regexp_replace(e.title, '[^\x00-\x7F]', ' ', 'g') 
     ) 

regexp_replace(e.title, '[^\x00-\x7F]', '?', 'g') est la clé où \x00-\x7F sont tous les caractères Unicode ne sont pas dans le schéma ASCII et 'g' continue à la recherche de plus de coups dans la même chaîne .