

CREATE OR REPLACE FUNCTION remove_diacritics( in_string TEXT )
	RETURNS TEXT
	LANGUAGE plpythonu
	AS
$$
	from unicodedata import normalize;
		
	_cache = SD.get('_remove_accents')
	if not _cache:
		#
		#	Setup cache for unicode entities
		#	This data is precalculated from unicodedata.name( an unicode character ) 
		#	so it pretty much covers all the unicode latin characters of interest
		#	including ligatures.
		#
		SD['_remove_accents'] = _cache = {	
					u'\u0133':'ij',	u'\u0153':'oe',	u'\ufb00':'ff',	u'\ufb01':'fi',	u'\ufb02':'fl',	u'\ufb03':'ffi',	u'\ufb04':'ffl',
					u'\ufb05':'st',	u'\ufb06':'st',	u'\u0132':'IJ',	u'\u0152':'OE', u'\xc6':'AE',  u'\xd8':'O',  u'\xe6':'ae',  u'\xf8':'o',  
					u'\u0110':'D',  u'\u0111':'d',  u'\u0126':'H',  u'\u0127':'h',  u'\u013f':'L',  u'\u0140':'l',  u'\u0141':'L',  u'\u0142':'l',  
					u'\u0149':'n',  u'\u0166':'T',  u'\u0167':'t',  u'\u0180':'b',  u'\u0181':'B',  u'\u0182':'B',  u'\u0183':'b',  u'\u0187':'C',  
					u'\u0188':'c',  u'\u018a':'D',  u'\u018b':'D',  u'\u018c':'d',  u'\u0191':'F',  u'\u0192':'f',  u'\u0193':'G',  u'\u0195':'hv',  
					u'\u0197':'I',  u'\u0198':'K',  u'\u0199':'k',  u'\u019a':'l',  u'\u019d':'N',  u'\u019e':'n',  u'\u019f':'O',  u'\u01a2':'OI',  
					u'\u01a3':'oi',  u'\u01a4':'P',  u'\u01a5':'p',  u'\u01ab':'t',  u'\u01ac':'T',  u'\u01ad':'t',  u'\u01ae':'T',  u'\u01b2':'V',  
					u'\u01b3':'Y',  u'\u01b4':'y',  u'\u01b5':'Z',  u'\u01b6':'z',  u'\u01c4':'DZ',  u'\u01c5':'D',  u'\u01c6':'dz',  
					u'\u01c7':'LJ',  u'\u01c8':'L',  u'\u01c9':'lj',  u'\u01ca':'NJ',  u'\u01cb':'N',  u'\u01cc':'nj',  u'\xc6':'AE',  
					u'\xe6':'ae',  u'\u01e4':'G',  u'\u01e5':'g',  u'\u01f1':'DZ',  u'\u01f2':'D',  u'\u01f3':'dz',  u'\xc6':'AE',  
					u'\xe6':'ae',  u'\xd8':'O',  u'\xf8':'o',  u'\u0220':'N',  u'\u0222':'OU',  u'\u0223':'ou',  u'\u0224':'Z',  
					u'\u0225':'z',  u'\u0253':'b',  u'\u0255':'c',  u'\u0256':'d',  u'\u0257':'d',  u'\u0260':'g',  u'\u0266':'h',  u'\u0268':'i',  
					u'\u026b':'l',  u'\u026c':'l',  u'\u026d':'l',  u'\u0271':'m',  u'\u0272':'n',  u'\u0273':'n',  u'\u027c':'r',  u'\u027d':'r',  
					u'\u027e':'r',  u'\u0282':'s',  u'\u0288':'t',  u'\u0289':'u',  u'\u028b':'v',  u'\u0290':'z',  u'\u0291':'z',  u'\u029d':'j',  u'\u02a0':'q',  
					u'\u02a3':'dz',  u'\u02a5':'dz',  u'\u02a6':'ts',  u'\u02a8':'tc',  u'\u02aa':'ls',  u'\u02ab':'lz',  u'\u0363':'a',  u'\u0364':'e',  u'\u0365':'i',  
					u'\u0366':'o',  u'\u0367':'u',  u'\u0368':'c',  u'\u0369':'d',  u'\u036a':'h',  u'\u036b':'m',  u'\u036c':'r',  u'\u036d':'t',  u'\u036e':'v',  
					u'\u036f':'x',  u'\u1e9a':'a',  u'\u2071':'i',  u'\u207f':'n',  u'\u249c':'a',  u'\u249d':'b',  u'\u249e':'c',  u'\u249f':'d',  u'\u24a0':'e',  
					u'\u24a1':'f',  u'\u24a2':'g',  u'\u24a3':'h',  u'\u24a4':'i',  u'\u24a5':'j',  u'\u24a6':'k',  u'\u24a7':'l',  u'\u24a8':'m',  u'\u24a9':'n',  
					u'\u24aa':'o',  u'\u24ab':'p',  u'\u24ac':'q',  u'\u24ad':'r',  u'\u24ae':'s',  u'\u24af':'t',  u'\u24b0':'u',  u'\u24b1':'v',  u'\u24b2':'w',  
					u'\u24b3':'x',  u'\u24b4':'y',  u'\u24b5':'z',  u'\u24b6':'A',  u'\u24b7':'B',  u'\u24b8':'C',  u'\u24b9':'D',  u'\u24ba':'E',  u'\u24bb':'F',  
					u'\u24bc':'G',  u'\u24bd':'H',  u'\u24be':'I',  u'\u24bf':'J',  u'\u24c0':'K',  u'\u24c1':'L',  u'\u24c2':'M',  u'\u24c3':'N',  u'\u24c4':'O',  
					u'\u24c5':'P',  u'\u24c6':'Q',  u'\u24c7':'R',  u'\u24c8':'S',  u'\u24c9':'T',  u'\u24ca':'U',  u'\u24cb':'V',  u'\u24cc':'W',  u'\u24cd':'X',  
					u'\u24ce':'Y',  u'\u24cf':'Z',  u'\u24d0':'a',  u'\u24d1':'b',  u'\u24d2':'c',  u'\u24d3':'d',  u'\u24d4':'e',  u'\u24d5':'f',  u'\u24d6':'g',  
					u'\u24d7':'h',  u'\u24d8':'i',  u'\u24d9':'j',  u'\u24da':'k',  u'\u24db':'l',  u'\u24dc':'m',  u'\u24dd':'n',  u'\u24de':'o',  u'\u24df':'p',  
					u'\u24e0':'q',  u'\u24e1':'r',  u'\u24e2':'s',  u'\u24e3':'t',  u'\u24e4':'u',  u'\u24e5':'v',  u'\u24e6':'w',  u'\u24e7':'x',  u'\u24e8':'y',  
					u'\u24e9':'z',  u'\uff21':'A',  u'\uff22':'B',  u'\uff23':'C',  u'\uff24':'D',  u'\uff25':'E',  u'\uff26':'F',  u'\uff27':'G',  u'\uff28':'H',  
					u'\uff29':'I',  u'\uff2a':'J',  u'\uff2b':'K',  u'\uff2c':'L',  u'\uff2d':'M',  u'\uff2e':'N',  u'\uff2f':'O',  u'\uff30':'P',  u'\uff31':'Q', 
					u'\uff32':'R',  u'\uff33':'S',  u'\uff34':'T',  u'\uff35':'U',  u'\uff36':'V',  u'\uff37':'W',  u'\uff38':'X',  u'\uff39':'Y',  u'\uff3a':'Z',  
					u'\uff41':'a',  u'\uff42':'b',  u'\uff43':'c',  u'\uff44':'d',  u'\uff45':'e',  u'\uff46':'f',  u'\uff47':'g',  u'\uff48':'h',  u'\uff49':'i',  
					u'\uff4a':'j',  u'\uff4b':'k',  u'\uff4c':'l',  u'\uff4d':'m',  u'\uff4e':'n',  u'\uff4f':'o',  u'\uff50':'p',  u'\uff51':'q',  u'\uff52':'r',  
					u'\uff53':'s',  u'\uff54':'t',  u'\uff55':'u',  u'\uff56':'v',  u'\uff57':'w',  u'\uff58':'x',  u'\uff59':'y',  u'\uff5a':'z'	 
				}
		
		# add to cache a precaculation of deaccented unicode characters
		# apply NFD normalization to every character
		# NFD decomposes an accented character as an unaccented character + the accent
		# we only keep the first character
		for x in xrange( 65536 ):
			c = unichr( x )
			if not c.isalnum( ):
				_cache[c] = ' '
			else:
				d = normalize('NFD',c)[0]
				if c != d:
					_cache[c] = d
				
	# use cache to process string
	return ''.join([ _cache.get(x,x) for x in unicode( in_string, 'utf-8' ) ]).encode( 'utf-8' )
		
$$;

CREATE OR REPLACE FUNCTION remove_non_alnum( s TEXT )
	RETURNS TEXT
	LANGUAGE plpythonu
	AS
$$
	return ''.join([ (' ',c)[ c.isalnum() ] for c in unicode( s, 'utf-8' ) ]).encode( 'utf-8' )
$$;

