Ca

Carateres em Julia

4 exercícios

Sobre Carateres

Este é um tema enorme! É possível escrever um livro longo sobre isto, e várias pessoas já o fizeram (procura "unicode book" na Amazon para ver alguns exemplos).

Uma história muito breve

Lidar com carateres nos computadores era muito mais simples nas décadas anteriores, quando os programadores assumiam que o inglês era a única língua importante. Então: 26 letras, maiúsculas e minúsculas, 10 algarismos, vários sinais de pontuação, mais um código (0x07) para fazer soar uma campainha, e tudo cabia em 7 bits: o conjunto de carateres ASCII.

Naturalmente, as pessoas começaram a perguntar o que fazer com à, ä e Ł, depois outras pessoas começaram a perguntar sobre ऄ, ஹ e ญ, e os jovens queriam emojis 😱. O que fazer?

Para encurtar a história, muitas pessoas inteligentes e pacientes tiveram de fazer parte de comités durante anos, a trabalhar nos detalhes do conjunto de carateres Unicode e de codificações como UTF-8, e muito software precisou de uma reescrita muito complicada. Além disso, foram introduzidos muitos bugs novos.

Para evitar que tudo se quebrasse, o desenho do Unicode/UTF-8 garante que os primeiros 127 códigos são idênticos ao ASCII (até a campainha).

Carateres em Julia

As linguagens concebidas depois de cerca de 2005 têm a enorme vantagem de já existir um padrão Unicode razoavelmente estável.

A Julia (lançada em 2012) pôde partir do princípio de que tudo seria Unicode: carateres, strings, nomes de variáveis e de funções, operadores matemáticos...

A citar o manual, "a Julia torna simples e eficiente lidar com texto ASCII simples, e lidar com Unicode é tão simples e eficiente quanto possível." Repara no "quanto possível", é uma parte importante da afirmação.

Os literais de caráter escrevem-se entre plicas, e são distintos das strings escritas entre aspas.

Isto é óbvio para quem vem do mundo do C/C++, mas pode ser confuso para programadores de Python e Javascript.

julia> a = 'a'  # Roman alphabet
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)

julia> typeof(a)
Char

julia> jha = 'झ'  # Devanagari alphabet
'झ': Unicode U+091D (category Lo: Letter, other)

julia> typeof(jha)
Char


julia> '❤'  # heart emoji
'❤': Unicode U+2764 (category So: Symbol, other)

Podemos ver pelos exemplos que o tipo é Char, e a Julia tem mais informações sobre a categoria do caráter.

A olhar com mais atenção, parece que estes carateres podem ser representados por 4 dígitos hexadecimais. O conjunto de carateres completo precisa de até 6 dígitos hexadecimais.

Estes números chamam-se "pontos de código" e vão atualmente de U+0000 a U+10FFFF. Aparecem no REPL, mas dentro do código usa codepoints() para os obter.

Converter entre Char e Int é simples:

julia> Int('a')
97

julia> Char(97)
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)

O compilador permite algumas formas de aritmética de inteiros com Chars:

julia> 'b' - 'a'  # interval, in alphabetic order
1

julia> 'b' + 'a'
ERROR: MethodError: no method matching +(::Char, ::Char)

julia> 'a' + 5
'f': ASCII/Unicode U+0066 (category Ll: Letter, lowercase)

julia> 'f' + ('A' - 'a')  # same as `uppercase('f')`
'F': ASCII/Unicode U+0046 (category Lu: Letter, uppercase)

Funções para carateres

Um subconjunto das funções de manipulação de strings também funciona com Char como entrada.

islowercase('A')  # false
uppercase('γ')  # 'Γ': Unicode U+0393 (category Lu: Letter, uppercase)
ispunct('@')  # true
isdigit('A')  # false
isxdigit('A')  # true

Para verificar se um caráter está presente numa string, temos o in. Repara que isto é diferente de substrings:

# char search
julia> 'a' ∈ "xabcahliazlnkiw"
true

# substring search
julia> "a" ∈ "xabcahliazlnkiw"
use occursin(needle, haystack) for string containment

Além disso, as expressões regulares (o tema de outro Conceito) permitem pesquisas e manipulações poderosas.

Conversões entre vetores de Char e strings

Para converter uma string num vetor de Char, podemos usar collect().

Para converter um vetor de Char numa string, existe o construtor String().

julia> s = "abcde"
"abcde"

julia> cv = collect(s)
5-element Vector{Char}:
 'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
 'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
 'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
 'd': ASCII/Unicode U+0064 (category Ll: Letter, lowercase)
 'e': ASCII/Unicode U+0065 (category Ll: Letter, lowercase)

julia> String(cv)
"abcde"

Isto funciona com quaisquer carateres, não apenas com ASCII.

julia> collect("❤,😱")
3-element Vector{Char}:
 '❤': Unicode U+2764 (category So: Symbol, other)
 ',': ASCII/Unicode U+002C (category Po: Punctuation, other)
 '😱': Unicode U+1F631 (category So: Symbol, other)

Repara que o construtor String() opera sobre um vetor. Para converter um único Char numa string de um caráter, a função é string(), com s minúsculo.

julia> string('a')
"a"

Armazenamento

Tudo o que vimos até agora neste documento parece relativamente simples, por isso será que há realmente pouco com que nos preocuparmos?

Infelizmente, isto é demasiado otimista!

Uma complicação vem da necessidade de "até" 6 algarismos hexadecimais por ponto de código. Isto significa que carateres diferentes precisam de diferentes quantidades de espaço em memória quando codificados em UTF-8.

Um byte só consegue armazenar números (sem sinal) até 255, dois algarismos hexadecimais, por isso o UTF-8 usa um número variável de bytes (1 a 4) para armazenar um Char. Estas chamam-se "unidades de código", e a função ncodeunits() devolve o número necessário para um determinado caráter.

julia> codepoint(jha)  # jha 'झ' is defined in an earlier example
0x0000091d

julia> ncodeunits(jha)
3

julia> ncodeunits('a')  # ASCII character
1

julia> ncodeunits('😱')  # emoji
4

Além disso, nem tudo o que pode ser mostrado no ecrã tem o seu próprio ponto de código único. Alguns carateres visualmente distintos são considerados derivados de outros, por isso o Unicode trata-os como um caráter principal mais um modificador.

Editar via GitHub A ligação abre numa nova janela ou separador

Aprende Carateres

A prática está bloqueada

Desbloqueia mais 3 exercícios para praticares Carateres