Em JavaScript, os dados textuais são armazenados como strings. Não existe um tipo separado para um único caractere.
O formato interno das strings é sempre UTF-16, não está vinculado à codificação da página.
Vamos relembrar os tipos de citações.
As strings podem ser colocadas entre aspas simples, aspas duplas ou crases:
deixe single = 'entre aspas simples'; deixe double = "aspas duplas"; deixe crases = `crases`;
Aspas simples e duplas são essencialmente iguais. Os backticks, no entanto, nos permitem incorporar qualquer expressão na string, envolvendo-a em ${…}
:
função soma(a, b) { retornar a + b; } alerta(`1 + 2 = ${soma(1, 2)}.`); //1 + 2 = 3.
Outra vantagem de usar crases é que eles permitem que uma string ocupe várias linhas:
deixe guestList = `Convidados: * John * Pete * Mary `; alerta(listadeconvidados); // uma lista de convidados, múltiplas linhas
Parece natural, certo? Mas aspas simples ou duplas não funcionam desta forma.
Se os usarmos e tentarmos usar múltiplas linhas, ocorrerá um erro:
let guestList = "Convidados: // Erro: token inesperado ILEGAL * John";
As aspas simples e duplas vêm dos tempos antigos da criação da linguagem, quando a necessidade de strings multilinhas não era levada em consideração. Os backticks apareceram muito mais tarde e, portanto, são mais versáteis.
Os crases também nos permitem especificar uma “função de modelo” antes do primeiro crase. A sintaxe é: func`string`
. A função func
é chamada automaticamente, recebe a string e as expressões incorporadas e pode processá-las. Esse recurso é chamado de “modelos marcados”, raramente é visto, mas você pode ler sobre ele no MDN: Literais de modelo.
Ainda é possível criar strings multilinhas com aspas simples e duplas usando o chamado “caractere de nova linha”, escrito como n
, que denota uma quebra de linha:
let guestList = "Convidados:n * Johnn * Peten * Mary"; alerta(listadeconvidados); // uma lista multilinha de convidados, igual à acima
Como um exemplo mais simples, estas duas linhas são iguais, apenas escritas de forma diferente:
deixe str1 = "OlánMundo"; // duas linhas usando um "símbolo de nova linha" // duas linhas usando uma nova linha normal e crases deixe str2 = `Olá Mundo`; alerta(str1 == str2); // verdadeiro
Existem outros caracteres especiais menos comuns:
Personagem | Descrição |
---|---|
n | Nova linha |
r | Nos arquivos de texto do Windows, uma combinação de dois caracteres rn representa uma nova quebra, enquanto no sistema operacional não Windows é apenas n . Por razões históricas, a maioria dos softwares Windows também entende n . |
' , " , ` | Citações |
\ | Barra invertida |
t | Guia |
b , f , v | Backspace, Form Feed, Vertical Tab – mencionados por completude, vindos de tempos antigos, não usados hoje em dia (você pode esquecê-los agora). |
Como você pode ver, todos os caracteres especiais começam com uma barra invertida . Também é chamado de “personagem de escape”.
Por ser tão especial, se precisarmos mostrar uma barra invertida dentro da string, precisaremos dobrá-la:
alert( `A barra invertida: \` ); // A barra invertida:
As chamadas aspas “escapadas” '
, "
, `
são usadas para inserir uma aspa na mesma string entre aspas.
Por exemplo:
alert( 'Eu sou a Morsa!' ); // Eu sou a Morsa!
Como você pode ver, temos que preceder a aspa interna com a barra invertida '
, porque caso contrário isso indicaria o final da string.
É claro que apenas as aspas iguais às anexas precisam ser escapadas. Portanto, como uma solução mais elegante, poderíamos mudar para aspas duplas ou crases:
alert("Eu sou a Morsa!"); // Eu sou a Morsa!
Além desses caracteres especiais, há também uma notação especial para códigos Unicode u…
, raramente usada e abordada no capítulo opcional sobre Unicode.
A propriedade length
tem o comprimento da string:
alerta( `Meun`.comprimento ); //3
Observe que n
é um único caractere “especial”, então o comprimento é de fato 3
.
length
é uma propriedade
Pessoas com experiência em outros idiomas às vezes digitam errado chamando str.length()
em vez de apenas str.length
. Isso não funciona.
Observe que str.length
é uma propriedade numérica, não uma função. Não há necessidade de adicionar parênteses depois disso. Não .length()
, mas .length
.
Para obter um caractere na posição pos
, use colchetes [pos]
ou chame o método str.at(pos). O primeiro caractere começa na posição zero:
deixe str = `Olá`; //o primeiro caractere alerta(str[0]); //H alerta(str.at(0) ); //H //o último caractere alerta(str[str.comprimento - 1]); //ó alerta(str.at(-1) );
Como você pode ver, o método .at(pos)
tem a vantagem de permitir posição negativa. Se pos
for negativo, será contado a partir do final da string.
Então .at(-1)
significa o último caractere, e .at(-2)
é o anterior, etc.
Os colchetes sempre retornam undefined
para índices negativos, por exemplo:
deixe str = `Olá`; alerta(str[-2]); // indefinido alerta(str.at(-2) ); // eu
Também podemos iterar sobre caracteres usando for..of
:
for (deixe o caractere de "Olá") { alerta(caractere); // H,e,l,l,o (char se torna "H", depois "e", depois "l" etc) }
Strings não podem ser alteradas em JavaScript. É impossível mudar um personagem.
Vamos tentar mostrar que não funciona:
deixe str = 'Oi'; str[0] = 'h'; //erro alerta(str[0]); //não funciona
A solução usual é criar uma string totalmente nova e atribuí-la a str
em vez da antiga.
Por exemplo:
deixe str = 'Olá'; str = 'h' + str[1]; //substitui a string alerta(str); // oi
Nas seções a seguir veremos mais exemplos disso.
Os métodos toLowerCase() e toUpperCase() alteram o caso:
alert('Interface'.toUpperCase() ); // INTERFACE alerta('Interface'.toLowerCase() ); //interface
Ou, se quisermos um único caractere em minúscula:
alerta('Interface'[0].toLowerCase() ); // 'eu'
Existem várias maneiras de procurar uma substring dentro de uma string.
O primeiro método é str.indexOf(substr, pos).
Ele procura o substr
em str
, começando na posição dada pos
, e retorna a posição onde a correspondência foi encontrada ou -1
se nada puder ser encontrado.
Por exemplo:
deixe str = 'Widget com id'; alerta(str.indexOf('Widget') ); // 0, porque 'Widget' é encontrado no início alerta(str.indexOf('widget') ); // -1, não encontrado, a pesquisa diferencia maiúsculas de minúsculas alerta(str.indexOf("id") ); // 1, "id" é encontrado na posição 1 (..idget com id)
O segundo parâmetro opcional nos permite iniciar a pesquisa a partir de uma determinada posição.
Por exemplo, a primeira ocorrência de "id"
está na posição 1
. Para procurar a próxima ocorrência, vamos iniciar a busca a partir da posição 2
:
deixe str = 'Widget com id'; alerta( str.indexOf('id', 2) ) // 12
Se estivermos interessados em todas as ocorrências, podemos executar indexOf
em um loop. Cada nova chamada é feita com a posição após a partida anterior:
let str = 'Tão astuto quanto uma raposa, tão forte quanto um boi'; deixe alvo = 'como'; // vamos procurar seja pos = 0; enquanto (verdadeiro) { deixe encontradoPos = str.indexOf(alvo, pos); if (foundPos == -1) quebra; alert( `Encontrado em ${foundPos}` ); pos = encontradoPos + 1; // continua a busca a partir da próxima posição }
O mesmo algoritmo pode ser apresentado de forma mais curta:
let str = "Tão astuto quanto uma raposa, tão forte quanto um boi"; deixe alvo = "como"; seja pos = -1; while ((pos = str.indexOf(alvo, pos + 1)) != -1) { alerta(pos); }
str.lastIndexOf(substr, position)
Existe também um método semelhante str.lastIndexOf(substr, position) que pesquisa do final de uma string até o início.
Ele listaria as ocorrências na ordem inversa.
Há um pequeno inconveniente com indexOf
no teste if
. Não podemos colocá-lo no if
assim:
deixe str = "Widget com id"; if (str.indexOf("Widget")) { alerta("Encontramos"); //não funciona! }
O alert
no exemplo acima não aparece porque str.indexOf("Widget")
retorna 0
(o que significa que encontrou a correspondência na posição inicial). Certo, mas if
considera 0
como false
.
Então, devemos verificar -1
, assim:
deixe str = "Widget com id"; if (str.indexOf("Widget") != -1) { alerta("Encontramos"); //funciona agora! }
O método mais moderno str.includes(substr, pos) retorna true/false
dependendo se str
contém substr
.
É a escolha certa se precisarmos testar a partida, mas não precisarmos de sua posição:
alert("Widget com id".includes("Widget") ); // verdadeiro alert("Olá".includes("Tchau") ); // falso
O segundo argumento opcional de str.includes
é a posição para iniciar a pesquisa:
alerta("Widget".includes("id") ); // verdadeiro alerta("Widget".includes("id", 3) ); // false, da posição 3 não existe "id"
Os métodos str.startsWith e str.endsWith fazem exatamente o que dizem:
alerta("Widget".startsWith("Wid") ); // verdadeiro, "Widget" começa com "Wid" alerta("Widget".endsWith("get") ); // verdadeiro, "Widget" termina com "get"
Existem 3 métodos em JavaScript para obter uma substring: substring
, substr
e slice
.
str.slice(start [, end])
Retorna a parte da string de start
a (mas não incluindo) end
.
Por exemplo:
deixe str = "stringify"; alerta(str.slice(0, 5) ); // 'strin', a substring de 0 a 5 (não incluindo 5) alerta(str.slice(0, 1) ); // 's', de 0 a 1, mas não incluindo 1, então apenas caractere em 0
Se não houver segundo argumento, slice
vai até o final da string:
deixe str = "stringificar"; alerta(str.slice(2)); // 'ringify', da 2ª posição até o final
Valores negativos para start/end
também são possíveis. Eles significam que a posição é contada a partir do final da string:
deixe str = "stringify"; //começa na 4ª posição da direita, termina na 1ª da direita alerta(str.slice(-4, -1) ); // 'gif'
str.substring(start [, end])
Retorna a parte da string entre start
e end
(não incluindo end
).
É quase o mesmo que slice
, mas permite start
seja maior que end
(nesse caso, ele simplesmente troca os valores start
e end
).
Por exemplo:
deixe str = "stringificar"; // estes são iguais para substring alerta(str.substring(2, 6) ); // "anel" alerta(str.substring(6, 2) ); // "anel" // ...mas não para fatia: alerta(str.slice(2, 6) ); // "anel" (o mesmo) alerta(str.slice(6, 2) ); // "" (uma string vazia)
Argumentos negativos (ao contrário do slice) não são suportados, eles são tratados como 0
.
str.substr(start [, length])
Retorna a parte da string desde start
, com o length
fornecido.
Em contraste com os métodos anteriores, este nos permite especificar o length
em vez da posição final:
deixe str = "stringify"; alerta(str.substr(2, 4) ); // 'anel', a partir da 2ª posição obtém 4 caracteres
O primeiro argumento pode ser negativo, contando a partir do final:
deixe str = "stringify"; alerta(str.substr(-4, 2) ); // 'gi', a partir da 4ª posição obtém 2 caracteres
Este método reside no Anexo B da especificação da linguagem. Isso significa que apenas mecanismos Javascript hospedados em navegador devem suportá-lo e não é recomendado usá-lo. Na prática, é suportado em todos os lugares.
Vamos recapitular esses métodos para evitar qualquer confusão:
método | seleciona… | negativos |
---|---|---|
slice(start, end) | do start ao end (não incluindo end ) | permite negativos |
substring(start, end) | entre start e end (não incluindo end ) | valores negativos significam 0 |
substr(start, length) | desde start obtenha caracteres length | permite start negativo |
Qual escolher?
Todos eles podem fazer o trabalho. Formalmente, substr
tem uma pequena desvantagem: ele não é descrito na especificação principal do JavaScript, mas no Anexo B, que cobre recursos exclusivos do navegador que existem principalmente por razões históricas. Portanto, ambientes que não sejam de navegador podem não oferecer suporte a ele. Mas na prática funciona em qualquer lugar.
Das outras duas variantes, slice
é um pouco mais flexível, permite argumentos negativos e é mais curto para escrever.
Então, para uso prático basta lembrar apenas slice
.
Como sabemos no capítulo Comparações, as strings são comparadas caractere por caractere em ordem alfabética.
Embora existam algumas esquisitices.
Uma letra minúscula é sempre maior que a maiúscula:
alerta( 'a' > 'Z' ); // verdadeiro
Letras com sinais diacríticos estão “fora de ordem”:
alert( 'Österreich' > 'Zelândia' ); // verdadeiro
Isto pode levar a resultados estranhos se classificarmos esses nomes de países. Normalmente as pessoas esperariam que Zealand
viesse depois de Österreich
na lista.
Para entender o que acontece, devemos estar cientes de que strings em Javascript são codificadas em UTF-16. Ou seja: cada caractere possui um código numérico correspondente.
Existem métodos especiais que permitem obter o caractere do código e voltar:
str.codePointAt(pos)
Retorna um número decimal que representa o código do caractere na posição pos
:
// letras maiúsculas diferentes possuem códigos diferentes alerta("Z".codePointAt(0) ); //90 alerta("z".codePointAt(0) ); //122 alerta( "z".codePointAt(0).toString(16) ); // 7a (se precisarmos de um valor hexadecimal)
String.fromCodePoint(code)
Cria um caractere pelo seu code
numérico
alerta(String.fromCodePoint(90)); //Z alerta(String.fromCodePoint(0x5a)); // Z (também podemos usar um valor hexadecimal como argumento)
Agora vamos ver os caracteres com códigos 65..220
(alfabeto latino e um pouco mais) fazendo uma sequência deles:
deixe str = ''; para (seja i = 65; i <= 220; i++) { str += String.fromCodePoint(i); } alerta(str); // Saída: // ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~ € ‚ƒ„ // ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜ
Ver? Os caracteres maiúsculos vão primeiro, depois alguns caracteres especiais, depois os caracteres minúsculos e Ö
perto do final da saída.
Agora fica óbvio porque a > Z
.
Os caracteres são comparados pelo seu código numérico. O código maior significa que o caractere é maior. O código para a
(97) é maior que o código para Z
(90).
Todas as letras minúsculas vêm depois das maiúsculas porque seus códigos são maiores.
Algumas letras como Ö
se destacam do alfabeto principal. Aqui, seu código é maior que qualquer coisa de a
a z
.
O algoritmo “certo” para fazer comparações de strings é mais complexo do que pode parecer, porque os alfabetos são diferentes para idiomas diferentes.
Portanto, o navegador precisa conhecer o idioma para comparar.
Felizmente, os navegadores modernos suportam o padrão de internacionalização ECMA-402.
Ele fornece um método especial para comparar strings em diferentes idiomas, seguindo suas regras.
A chamada str.localeCompare(str2) retorna um número inteiro indicando se str
é menor, igual ou maior que str2
de acordo com as regras da linguagem:
Retorna um número negativo se str
for menor que str2
.
Retorna um número positivo se str
for maior que str2
.
Retorna 0
se forem equivalentes.
Por exemplo:
alert('Österreich'.localeCompare('Zelândia') ); // -1
Na verdade, este método possui dois argumentos adicionais especificados na documentação, o que permite especificar o idioma (por padrão retirado do ambiente, a ordem das letras depende do idioma) e configurar regras adicionais como distinção entre maiúsculas e minúsculas ou deveria "a"
e "á"
ser tratado como o mesmo etc.
Existem 3 tipos de cotações. Os crases permitem que uma string ocupe várias linhas e incorpore expressões ${…}
.
Podemos usar caracteres especiais, como uma quebra de linha n
.
Para obter um caractere, use: []
ou o método at
.
Para obter uma substring, use: slice
ou substring
.
Para colocar uma string em minúsculas/maiúsculas, use: toLowerCase/toUpperCase
.
Para procurar uma substring, use: indexOf
ou includes/startsWith/endsWith
para verificações simples.
Para comparar strings de acordo com o idioma, utilize: localeCompare
, caso contrário elas serão comparadas por códigos de caracteres.
Existem vários outros métodos úteis em strings:
str.trim()
– remove (“corta”) espaços do início e do final da string.
str.repeat(n)
– repete a string n
vezes.
…e mais pode ser encontrado no manual.
Strings também possuem métodos para pesquisar/substituir com expressões regulares. Mas esse é um assunto importante, por isso é explicado em uma seção separada do tutorial. Expressões regulares.
Além disso, a partir de agora é importante saber que as strings são baseadas na codificação Unicode e, portanto, há problemas com comparações. Há mais sobre Unicode no capítulo Unicode, String internals.
importância: 5
Escreva uma função ucFirst(str)
que retorne a string str
com o primeiro caractere maiúsculo, por exemplo:
ucPrimeiro("joão") == "João";
Abra uma sandbox com testes.
Não podemos “substituir” o primeiro caractere, porque strings em JavaScript são imutáveis.
Mas podemos fazer uma nova string baseada na existente, com o primeiro caracter maiúsculo:
deixe newStr = str[0].toUpperCase() + str.slice(1);
Porém, há um pequeno problema. Se str
estiver vazio, então str[0]
é undefined
e, como undefined
não possui o método toUpperCase()
, obteremos um erro.
A saída mais fácil é adicionar um teste para uma string vazia, assim:
função ucPrimeiro(str) { se (!str) retornar str; retornar str[0].toUpperCase() + str.slice(1); } alert(ucFirst("joão") ); // John
Abra a solução com testes em uma sandbox.
importância: 5
Escreva uma função checkSpam(str)
que retorne true
se str
contém 'viagra' ou 'XXX', caso contrário false
.
A função deve diferenciar maiúsculas de minúsculas:
checkSpam('compre ViAgRA agora') == true checkSpam('xxxxx grátis') == verdadeiro checkSpam("coelho inocente") == falso
Abra uma sandbox com testes.
Para tornar a pesquisa insensível a maiúsculas e minúsculas, vamos colocar a string em minúsculas e depois pesquisar:
função verificarSpam(str) { deixe lowerStr = str.toLowerCase(); return lowerStr.includes('viagra') || lowerStr.includes('xxx'); } alert(checkSpam('compre ViAgRA agora') ); alerta(checkSpam('xxxxx grátis') ); alert(checkSpam("coelho inocente") );
Abra a solução com testes em uma sandbox.
importância: 5
Crie uma função truncate(str, maxlength)
que verifica o comprimento do str
e, se exceder maxlength
– substitui o final de str
pelo caractere de reticências "…"
, para tornar seu comprimento igual a maxlength
.
O resultado da função deve ser a string truncada (se necessário).
Por exemplo:
truncate("O que eu gostaria de dizer sobre este tópico é:", 20) == "O que eu gostaria de dizer…" truncate("Olá a todos!", 20) == "Olá a todos!"
Abra uma sandbox com testes.
O comprimento máximo deve ser maxlength
, então precisamos cortá-lo um pouco mais curto, para dar espaço para as reticências.
Observe que, na verdade, existe um único caractere Unicode para reticências. Isso não são três pontos.
função truncar(str, maxlength) { retornar (str.length > maxlength)? str.slice(0, comprimento máximo - 1) + '…' : str; }
Abra a solução com testes em uma sandbox.
importância: 4
Temos um custo no formato "$120"
. Ou seja: primeiro vem o cifrão e depois o número.
Crie uma função extractCurrencyValue(str)
que extrairia o valor numérico dessa string e o retornaria.
O exemplo:
alerta(extrairCurrencyValue('$120') === 120 ); // verdadeiro
Abra uma sandbox com testes.
function extrairValorMoeda(str) { retornar +str.slice(1); }
Abra a solução com testes em uma sandbox.