У меня есть строка типа кафе, и мне нужно перевести ее в кафе.
Я пробовал (string-normalize-nfd "café")
, но он возвращает кафе кавычки с акцентом, а `(string-normalize-nfd alguém) возвращает alguem с акцентом на м.
Как я могу перевести строку с ударением в строку без ударения?
Я не могу придумать встроенную процедуру, которая делает то, что вам нужно, но легко написать свою собственную реализацию:
; maps accented chars to unaccented chars
(define translate
'#hash((#\á . #\a)
(#\é . #\e)
(#\í . #\i)
(#\ó . #\o)
(#\ú . #\u)))
(define (remove-accents str)
(apply string ; convert char list back into string
; for each char: replace it with non-accented
; version, if not present leave it unmodified
(map (λ (c) (hash-ref translate c (const c)))
(string->list str)))) ; convert string to char list
Не забудьте добавить дополнительные сопоставления по мере необходимости, например, для включения символов в верхнем регистре и т. д. Это работает, как ожидалось:
(remove-accents "café")
=> "cafe"
На самом деле ваш вопрос не о Racket; это о нормализации Unicode. Функция, о которой вы говорите, выполняет «каноническую нормализацию», описанную на эта страница.
Мне кажется, что лучший способ сделать то, что вы хотите, - это выполнить нормализацию, а затем удалить любые символы с диакритическими знаками, если вы знаете, что исходная строка не содержит символов с диакритическими знаками.
У вас есть правильная идея использовать string-normalize-nfd
- и он действительно работает! Просто строки Racket имеют кодировку UTF-8 и печатаются как составные или разложенные одинаково.
(string-normalize-nfd "café") ;Racket prints UTF-8 string as "café"
Вы можете увидеть, что это сработало, если преобразовать строку в байты:
(string->bytes/utf-8 (string-normalize-nfd "café")) ;#"cafe\314\201"
Учитывая это, вот черновой вариант функции. Я был бы удивлен, если бы это были абсолютно правильными для всех случаев. Но, надеюсь, этого достаточно, чтобы получить вы на своем пути, и вы можете его усовершенствовать.
(define (ascii-ize s)
(list->string
(for/list ([b (in-bytes (string->bytes/utf-8
(string-normalize-nfd s)))]
#:when (< b 128))
(integer->char b))))
(ascii-ize "café") ;"cafe"
(ascii-ize "alguém") ;"alguem"
Вы можете использовать iconv