# Accents and String#tr

**URL:** <https://www.ruby-forum.com/t/accents-and-string-tr/71085>\
**Category:** Ruby\
**Created:** [February 21, 2006, 12:28am UTC](https://www.ruby-forum.com/t/accents-and-string-tr/71085 "2006-02-21T00:28:13Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![fxn](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/77aa72/32.png) [@fxn](https://www.ruby-forum.com/u/fxn)\
**Post date:** [February 21, 2006, 12:28am UTC](https://www.ruby-forum.com/t/accents-and-string-tr/71085/1 "2006-02-21T00:28:13Z")

</div>

I wrote this method

def self.normalize\_for\_sorting(s)  
return nil unless s  
norm = s.downcase  
norm.tr!(‘ÁÉÍÓÚ’, ‘aeiou’)  
norm.tr!(‘ÀÈÌÒÙ’, ‘aeiou’)  
norm.tr!(‘ÄËÏÖÜ’, ‘aeiou’)  
norm.tr!(‘ÂÊÎÔÛ’, ‘aeiou’)  
norm.tr!(‘áéíóú’, ‘aeiou’)  
norm.tr!(‘àèìòù’, ‘aeiou’)  
norm.tr!(‘äëïöü’, ‘aeiou’)  
norm.tr!(‘âêîôû’, ‘aeiou’)  
norm  
end

to normalize strings for sorting. This script is UTF-8, everything is  
UTF-8 in my application, $KCODE is ‘u’.

But it does not work, examples:

```
Andrés -> andruos
López -> luupez
Pérez -> puorez

```

I tried to “force” it with Iconv.conv(‘UTF-8’, ‘ASCII’, ‘aeiou’) to  
no avail. Any ideas?

– fxn

---

<div class="post-metadata">

**Author:** ![fxn](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/77aa72/32.png) [@fxn](https://www.ruby-forum.com/u/fxn)\
**Post date:** [February 21, 2006, 3:54am UTC](https://www.ruby-forum.com/t/accents-and-string-tr/71085/2 "2006-02-21T03:54:02Z")

</div>

DÅ?a Utorok 21 FebruÃ¡r 2006 00:28 Xavier N. napÃ­sal:

> ```
> norm.tr!('Ã Ã¨Ã¬Ã²Ã¹', 'aeiou')
> AndrÃ©s -> andruos
> LÃ³pez -> luupez
> PÃ©rez -> puorez
> 
> ```
> 
> I tried to “force” it with Iconv.conv(‘UTF-8’, ‘ASCII’, ‘aeiou’) to  
> no avail. Any ideas?
> 
> – fxn

Apparently, not all String methods were created equal:

david@chello082119107152:~$ irb  
irb(main):001:0\> $KCODE = ‘u’  
=\> “u”  
irb(main):002:0\> require ‘jcode’  
=\> true  
irb(main):003:0\> “AndrÃ©s”.tr(“Ã¡Ã©Ã­Ã³Ãº”, “aeiou”)  
=\> “Andres”

jcode to the rescue!

David V.

---

<div class="post-metadata">

**Author:** ![fxn](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/77aa72/32.png) [@fxn](https://www.ruby-forum.com/u/fxn)\
**Post date:** [February 21, 2006, 2:55pm UTC](https://www.ruby-forum.com/t/accents-and-string-tr/71085/3 "2006-02-21T14:55:07Z")

</div>

Xavier N. wrote:

> ```
> norm.tr!('àèìòù', 'aeiou')
> 
> ```
> 
> Andrés -\> andruos  
> López -\> luupez  
> Pérez -\> puorez
> 
> I tried to “force” it with Iconv.conv(‘UTF-8’, ‘ASCII’, ‘aeiou’) to no  
> avail. Any ideas?
> 
> – fxn

Hi,

My guess is that the “tr” method treats its arguments as a string of  
bytes. And because characters with accents need more than 1 byte in  
UTF-8, #tr doesn’t do what you would expect it to. (It’s not even tr’s  
fault, how is it supposed to know that two bytes actually represent a  
single character?)

The solution is not to use #tr!, but #gsub!. It isn’t as short, but at  
least it’s right 😉

norm.gsub!(‘ä’, ‘a’)  
norm.gsub!(‘ë’, ‘e’)

# and so on…

And because that is against DRY (Don’t Repeat Yourself), I would  
recommend storing the mapping as a hash:

accents = { ‘ä’ =\> ‘a’, ‘ë’ =\> ‘e’, … }  
accents.each do |accent, replacement|  
norm.gsub!(accent, replacement)  
end

Regards,  
Robin S.
