96

How to remove diacritics (or accents) from a String (like say change "één" to "een") in Swift? Do I have to go back to NSString or can it be done within Swift?

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
Johan Kool
  • 15,637
  • 8
  • 64
  • 81

5 Answers5

196

You can operate directly on a Swift String (if "Foundation" is imported):

let foo = "één"
let bar = foo.stringByFoldingWithOptions(.DiacriticInsensitiveSearch, locale: NSLocale.currentLocale())
print(bar) // een

Swift 3:

let foo = "één"
let bar = foo.folding(options: .diacriticInsensitive, locale: .current)
print(bar) // een
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Excellent answer as always. Note that stringByFoldingWithOptions is a method from NSString. This takes advantage of the seamless bridging between NSString and String in Swift 2. Things are different in Swift 3. – Duncan C Oct 28 '16 at 11:14
  • 3
    @codddeer123: Looks like similar case as in https://stackoverflow.com/a/16837527/1187415: U-0141 LATIN CAPITAL LETTER L WITH STROKE does not have a decomposition into a base character and a combining mark. Or (as I understand it) the Unicode standard does not define a relationship between `Ł` and `L`. – Martin R Apr 09 '18 at 19:13
  • @MartinR, thanks for quick response. So in case of Ł i should remove it manually? – mikro098 Apr 09 '18 at 19:17
  • @codddeer123: I do not know a better solution. – Martin R Apr 09 '18 at 19:25
  • This is fantastic! If I set it with "locale: .current" and then the app is used in a country where the current locale supports some type of accented character, will that make a difference? Is there a difference in making this call with "locale: nil" vs .current? – RanLearns May 24 '18 at 17:30
  • 2
    @RanLearns: I *assume* that `locale: nil` will apply the general Unicode rules, and `locale: .current` those of the current languages. But I have not tested it. – Martin R May 24 '18 at 19:52
  • @MartinR `Locale: nil` uses the system locale. – xian Apr 28 '19 at 11:40
  • I tried, any to keep space in result String? – Kien Vu Jul 26 '21 at 04:07
23

Update to @MartinR's answer… a Swift 3 extension to provide a string for sorting / searching, that might be useful for someone…

extension String {
    var forSorting: String {
        let simple = folding(options: [.diacriticInsensitive, .widthInsensitive, .caseInsensitive], locale: nil)
        let nonAlphaNumeric = CharacterSet.alphanumerics.inverted
        return simple.components(separatedBy: nonAlphaNumeric).joined(separator: "")
    }
}

e.g.

print("Mÿ nâMe ís jÄço´B".forSorting) // "mynameisjacob"
Ashley Mills
  • 50,474
  • 16
  • 129
  • 160
  • 1
    You should now that sorting is very locale dependent. For example, in my language "ch" is one letter between "h" "i". For sorting thay is diacritics insensitive just use the correct string search options. – Sulthan Oct 27 '16 at 10:36
  • 7
    For sorting you should use `localizedStandardCompare`. – rmaddy May 29 '18 at 17:15
9

This is my solutión

Swift 5

    extension String {

        func unaccent() -> String {

            return self.folding(options: .diacriticInsensitive, locale: .current)

        }

    }
Danielvgftv
  • 547
  • 7
  • 6
7

This can also be done applying a StringTransform:

let foo = "één"
let bar = foo.applyingTransform(.stripDiacritics, reverse: false)!
print(bar) // een

Or implementing a custom property to StringProtocol

extension StringProtocol {
    var stripingDiacritics: String {
        applyingTransform(.stripDiacritics, reverse: false)!
    }
}

let bar = foo.stripingDiacritics
print(bar) // een
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
0

Answer update for Swift 5.0.1

func toNoSmartQuotes() -> String {
    let userInput: String = self
    return userInput.folding(options: .diacriticInsensitive, locale: .current)
}

and use it someTextField.text.toNoSmartQuotes()

amagain
  • 2,042
  • 2
  • 20
  • 36