Uma String em Julia é uma sequência ordenada de carateres. Como o manual assinala: «Claro que a verdadeira dificuldade surge quando nos perguntamos o que é um caráter.»
Grande parte desta complexidade será abordada com mais detalhe no Conceito Chars, mas, resumidamente:
Em geral, as strings são delimitadas por aspas duplas " ".
As aspas simples ' ' só se usam para Chars.
Também é possível usar aspas duplas triplas """ """, o que permite usar " dentro da string sem escapes.
Mais importante ainda, a indentação extra indesejada é removida das strings com várias linhas.
julia> """
Multiline
"""
"Multiline\nString\n"
Como a maioria das linguagens a partir de C, Julia usa uma barra invertida \ para escapar carateres:
\n do exemplo anterior.\$ (ver abaixo).Em princípio, as strings podem ser indexadas exatamente como vetores:
julia> s[1], s[5]
('J', 'a')
Isto funciona claramente para uma string ASCII como "Julia", mas ignora a maioria das línguas do mundo.
Considera um dos carateres de Beowulf, escrito em inglês antigo há cerca de 15 séculos.
"Hrōðgār" tem claramente 7 carateres, mas nem todos são ASCII.
julia> king = "Hrōðgār"
"Hrōðgār"
julia> length(king)
7
julia> isascii(king)
false
# collect() converts to a Char vector:
julia> collect(king)
7-element Vector{Char}:
'H': ASCII/Unicode U+0048 (category Lu: Letter, uppercase)
'r': ASCII/Unicode U+0072 (category Ll: Letter, lowercase)
'ō': Unicode U+014D (category Ll: Letter, lowercase)
'ð': Unicode U+00F0 (category Ll: Letter, lowercase)
'g': ASCII/Unicode U+0067 (category Ll: Letter, lowercase)
'ā': Unicode U+0101 (category Ll: Letter, lowercase)
'r': ASCII/Unicode U+0072 (category Ll: Letter, lowercase)
Indexar uma string como esta começa bem, mas a certa altura deixa de funcionar:
julia> king[3]
'ō': Unicode U+014D (category Ll: Letter, lowercase)
julia> king[4]
ERROR: StringIndexError: invalid index [4], valid nearby indices [3]=>'ō', [5]=>'ð'
O problema é que indexar assim conta bytes, que, no caso das strings não ASCII, não têm uma relação de 1:1 com os carateres.
Um caráter Unicode/UTF-8 pode precisar de até 4 bytes para ser representado, e o Conceito Chars vai explorar isto mais a fundo.
Muitas linguagens usam + como operador de concatenação de strings, mas Julia não.
Pelo menos, a mensagem de erro é útil.
julia> "s1 " + "s2"
ERROR: MethodError: no method matching +(::String, ::String)
The function `+` exists, but no method is defined for this combination of argument types.
String concatenation is performed with *
julia> "s1 " * "s2"
"s1 s2"
A função string() concatena um número arbitrário de strings.
julia> string("lots ", "of ", "bits")
"lots of bits"
A função join() faz o mesmo e também aceita um vetor de strings, concatenando-as com um separador indicado (por omissão, "").
julia> join(["lots", "of", "bits"], "_")
"lots_of_bits"
Repara que as strings são imutáveis e que a concatenação implica cópias. Por isso, concatenações repetidas dentro de um ciclo são ineficientes, e é melhor reunir os fragmentos num vetor e juntá-los todos no fim.
Simples:
julia> repeat("Abc", 5)
"AbcAbcAbcAbcAbc"
Muitas linguagens têm uma forma de inserir valores calculados nas strings, embora haja um desacordo extraordinário sobre a melhor sintaxe a usar.
Em Julia, os valores interpolados são precedidos por $.
julia> myvar = 42
42
julia> "myvar evaluates to $myvar"
"myvar evaluates to 42"
julia> r = 5.3
5.3
julia> "A circle of radius $r has area $(π * r^2)"
"A circle of radius 5.3 has area 88.24733763933729"
Os parênteses são obrigatórios quando omiti-los seria ambíguo, mas são opcionais para um único identificador seguido de espaço em branco.
Para incluir um $ na string, escapa-o como \$.
Repara na limitação de que a interpolação, atualmente, não permite formatação, como o número de casas decimais a apresentar.
@sprintf()Para um controlo mais fino sobre a construção de strings, Julia copia a função sprintf do C (e de várias linguagens posteriores: a Wikipédia lista cerca de 30).
Em Julia, isto está implementado como uma macro dentro do módulo Printf, daí o prefixo @.
julia> using Printf
julia> r = 5.3
5.3
julia> @sprintf("A circle of radius %.1f has area %.2f", r, π * r^2)
"A circle of radius 5.3 has area 88.25"
Por simplicidade, esta secção vai centrar-se nas funções que devolvem uma nova string e deixam o valor de entrada inalterado.
Muitas têm um equivalente, com o sufixo !, que modifica o valor de entrada no próprio local.
Qual é o comprimento de uma string? Às vezes, depende de como contas.
O caso simples são as strings ASCII, em que cada caráter ocupa 1 byte.
julia> string_asc = "Julia"
"Julia"
julia> length(string_asc)
5
julia> sizeof(string_asc)
5
A função length() devolve o número de carateres, e a função sizeof(), o número de bytes.
Esta distinção torna-se importante com outros conjuntos de carateres:
julia> king = "Hrōðgār"
"Hrōðgār"
julia> length(king)
7
julia> sizeof(king)
10
Uma operação comum em programação é pegar numa string longa e dividi-la em pedaços, com base numa string separadora de um ou mais carateres.
De um modo mais geral, usamos a função split().
O separador, por omissão, é qualquer espaço em branco, mas podem indicar-se outros.
julia> split("my little string")
3-element Vector{SubString{String}}:
"my"
"little"
"string"
julia> split("My_snake_case_string", "_")
4-element Vector{SubString{String}}:
"My"
"snake"
"case"
"string"
Estes exemplos dividem uma string em strings mais pequenas. Dividir uma string em carateres é uma operação diferente.
Uma string contém uma substring especificada?
Curiosamente, há duas funções para testar isto: occursin() e contains() diferem apenas na ordem dos seus argumentos.
julia> needle = "Julia"
"Julia"
julia> haystack = "Python, Julia and R"
"Python, Julia and R"
julia> occursin(needle, haystack)
true
julia> contains(haystack, needle)
true
Para sermos mais específicos quanto à posição:
julia> startswith(haystack, "Python")
true
julia> endswith(haystack, "Python")
false
Para obter os índices início:fim de uma substring, temos várias funções:
findfirst()findlast()findprev()findnext()julia> findfirst(needle, haystack)
9:13
Para substituir substrings, lista as alterações com a sintaxe x => y.
julia> replace("abc", "a"=>"b", "b"=>"c", "c"=>"a")
"bca"
Desde a Julia 1.7, a função replace pode receber um número arbitrário de alterações, com a garantia de que nenhum caráter será alterado mais do que uma vez durante a substituição.
A sintaxe x => y chama-se pair, um tipo importante em Julia, abordado com mais detalhe no Conceito Dicts and Pairs.
Muitas vezes, precisamos de remover os espaços em branco do início e/ou do fim de uma string.
As funções para isto são lstrip() (esquerda), rstrip() (direita) e strip() (ambos).
julia> strip("\n\t useful_bit\n\n")
"useful_bit"
Estas funções têm nomes bastante autoexplicativos:
julia> s = repeat("aBcD ", 5)
"aBcD aBcD aBcD aBcD aBcD "
julia> uppercase(s)
"ABCD ABCD ABCD ABCD ABCD "
julia> lowercase(s)
"abcd abcd abcd abcd abcd "
julia> titlecase(s) # Initial letter of each word uppercase
"Abcd Abcd Abcd Abcd Abcd "
Neste exercício vais processar linhas de registo.
Cada linha de registo é uma string formatada da seguinte forma: "[<LEVEL>]: <MESSAGE>".
Há três níveis de registo diferentes:
INFOWARNINGERRORTens três tarefas e cada uma recebe uma linha de registo e pede-te que faças algo com ela.
Implementa a função message para devolver a mensagem de uma linha de registo:
julia> message("[ERROR]: Invalid operation")
"Invalid operation"
Qualquer espaço em branco no início ou no fim deve ser removido:
julia> message("[WARNING]: Disk almost full\r\n")
"Disk almost full"
Implementa a função log_level para devolver o nível de registo de uma linha, que deve ser devolvido em minúsculas:
julia> log_level("[ERROR]: Invalid operation")
"error"
Implementa a função reformat, que reformata a linha de registo, colocando a mensagem primeiro e o nível de registo depois, entre parênteses:
julia> reformat("[INFO]: Operation completed")
"Operation completed (info)"
Nota: Todas as strings deste exercício estão em inglês e limitadas ao conjunto de carateres ASCII. Os próximos conceitos darão a oportunidade de trabalhar com carateres Unicode.
Inscreve-te no Exercism para aprenderes e dominares Julia com 35 conceitos128 exercícios, e mentoria humana real, tudo grátis.