Skip to content

6. As cadeias de caracteres

As cadeias de caracteres do JavaScript são muito semelhantes às do PHP.

Image

6.1. script [str-01]

A primeira coisa a compreender é que, uma vez criada, uma cadeia de caracteres já não é modificável. Existem vários métodos para produzir uma nova cadeia a partir da cadeia inicial, mas esta permanece sempre inalterada. Além disso, uma cadeia de caracteres pode ser de dois tipos:

  • [string] quando é inicializada com uma cadeia literal;
  • [object] quando é criada como instância da classe [String];

''use strict';

// as cadeias de caracteres são de leitura única (não podem ser alteradas)

// uma cadeia de caracteres
const chaîne1 = "abcd ";
// tipo
console.log("typeof(chaîne1)=", typeof (chaîne1));
// caractere n.º 2
console.log("chaîne1[2]=", chaîne1[2]);
// provoca um erro
chaîne1[2] = "0";

Execução


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Temp\19-09-01\javascript\strings\str-01.js"
typeof(chaîne1)= string
chaîne1[2]= c
c:\Temp\19-09-01\javascript\strings\str-01.js:1
TypeError: Cannot assign to read only property '2' of string 'abcd '
at Object.<anonymous> (c:\Temp\19-09-01\javascript\strings\str-01.js:12:12)
at Generator.next (<anonymous>)

6.2. script [str-02]

Este script demonstra que é possível construir uma cadeia de caracteres de duas formas.


''use strict';

// as cadeias de caracteres podem ser de dois tipos

// uma cadeia literal
const chaîne1 = "abcd ";
// tipo
console.log("typeof(chaîne1)=", typeof (chaîne1));
// instância de String
const chaîne2 = new String("xyzt");
// tipo
console.log("typeof(chaîne2)=", typeof (chaîne2));
// outra forma de escrita (sem «new») – tipo [string] e não [object]
const chaîne3 = String("12 34");
// tipo
console.log("typeof(chaîne3)=", typeof (chaîne3));
// o tipo [string] e o tipo [object] oferecem os mesmos métodos, os da classe String
console.log("chaîne1.length=", chaîne1.length);
console.log("chaîne2.length=", chaîne2.length);

Comentários

  • linha 6: o método habitual de definição de uma cadeia de caracteres. [chaîne1] será do tipo [string];
  • linha 10: é possível construir uma cadeia de caracteres utilizando o construtor da classe [String]. [chaîne2] será do tipo [object];

Execução


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\strings\str-02.js"
typeof(chaîne1)= string
typeof(chaîne2)= object
typeof(chaîne3)= string
chaîne1.length= 5
chaîne2.length= 4

O tipo [string] beneficia dos métodos da classe [String].

6.3. script [str-03]

Este script apresenta uma cadeia de caracteres específica com interpolação de variáveis.


'use strict';

// cadeia
const chaîne = "Introduction à Javascript par l'exemple";
// cadeia com interpolação de variáveis
const str = `[${chaîne}].substr(3, 2)=` + chaîne.substr(3, 2)
console.log(str);

Comentários

  • linha 6: é possível ter cadeias de caracteres que contenham expressões ${variável}, as quais são substituídas pelo valor da variável. Trata-se da mesma lógica que as variáveis $ nas cadeias de caracteres PHP. Note-se a notação de uma cadeia deste tipo: está entre «backstick» ou apóstrofo invertido (AltGr-7 num teclado francês);

Execução


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Temp\19-09-01\javascript\strings\tempCodeRunnerFile.js"
[Introduction à Javascript par l'exemple].substr(3, 2)=ro

6.4. script [str-04]

A cadeia de caracteres com interpolação de variáveis continua a ser insuficiente. Com efeito, não é possível substituir a variável na expressão ${variable} por uma expressão. Para quem já programou em C, não há nada como as funções [printf, sprintf] para escrever ou construir cadeias de caracteres formatadas. Centenas de programadores desenvolveram milhares de pacotes JavaScript, formando um ecossistema imenso. Quando existe uma necessidade que não é satisfeita nativamente pelo JavaScript, é altura de procurar um pacote que a satisfaça. Para isso, utilizamos o gestor de pacotes [npm]. Este dispõe de uma opção [search] que permite procurar uma cadeia de caracteres na descrição dos pacotes. [npm] devolve a lista de pacotes que correspondem à pesquisa. Vamos, portanto, procurar a cadeia [sprintf] na descrição dos pacotes:

Image

  • na coluna [4], as palavras-chave dos pacotes da coluna [3];
  • na coluna [5], a descrição dos pacotes da coluna [3];

O passo seguinte é aceder ao site da ferramenta [npm], [https://www.npmjs.com/] e ler a descrição dos pacotes:

Image

No [3], analisa-se a lista de pacotes e escolhe-se um.

Image

Na descrição do pacote, encontram-se as informações para o instalar e utilizar:

Image

Instalamos o pacote [sprintf-js] num terminal do [VSCode]:

Image

Esta instalação irá alterar o ficheiro [package.json] localizado na raiz da pasta [javascript] [2]:

Image

Como se pode ver acima, o pacote foi instalado nos [dependencies], ou seja, nos pacotes necessários para a execução do projeto. Recorde-se que os pacotes necessários são colocados em [devDependencies] apenas durante o desenvolvimento do projeto. Não são utilizados durante a execução. Esta diferença é importante quando é necessário criar a versão final do projeto para a sua entrada em produção. Existem ferramentas para:

  • reunir todos os ficheiros jS necessários à execução num único ficheiro. Os pacotes [devDependencies] não são, portanto, incluídos neste ficheiro final;
  • minificar esse ficheiro, ou seja, reduzir o seu tamanho ao mínimo possível. Para tal, por exemplo, todos os comentários são eliminados;
  • «ofuscar» o código para o tornar difícilmente compreensível. Por exemplo, as variáveis taxa, salário e imposto serão substituídas pelas variáveis a, b e c;
  • e realizar outras otimizações;

Esta otimização do ficheiro final de um projeto jS é utilizada na programação web. Uma aplicação web pode depender de um grande número de ficheiros JavaScript. O carregamento destes por um navegador pode atrasar a exibição da primeira página da aplicação. A otimização anterior visa melhorar esse tempo de carregamento. Se o tempo de carregamento for considerado demasiado longo pelos utilizadores, a aplicação não será utilizada.

Agora que dispomos do pacote [sprintf-js], temos de o utilizar. Trata-se do script [str-04]:


'use strict';
// utilização de um pacote externo para dispor da função sprintf
import { sprintf } from 'sprintf-js';
// cadeia
const chaîne = "Introduction à Javascript par l'exemple";
// método
console.log(sprintf("[%s].substr(3,2)=[%s]", chaîne, chaîne.substr(3, 2)));

Com o ECMAScript 6, utiliza-se a palavra-chave [import] para importar um objeto exportado por um pacote. Para saber o que o pacote exporta, pode-se consultar o seu código:

Image

  • no [1], clicar com o botão direito do rato no pacote importado;
  • no [2], queremos ver a definição;
  • em [3-4], verifica-se que o pacote exporta uma função chamada [sprintf];

A função [sprintf] do pacote [sprintf-js] é importada com a instrução:


import { sprintf } from 'sprintf-js';

O código completo:


'use strict';
// utilização de um pacote externo para aceder à função sprintf
import { sprintf } from 'sprintf-js';
// cadeia
const chaîne = "Introduction à Javascript par l'exemple";
// método
console.log(sprintf("[%s].substr(3,2)=[%s]", chaîne, chaîne.substr(3, 2)));

produz os seguintes resultados:


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\strings\str-04.js"
c:\Temp\19-09-01\javascript\strings\str-04.js:3
import { sprintf } from 'sprintf-js';
^

SyntaxError: Unexpected token {
at new Script (vm.js:79:7)
at createScript (vm.js:251:10)
at Object.runInThisContext (vm.js:303:10)
at Module._compile (internal/modules/cjs/loader.js:657:28)

Na linha 3, a instrução [import] não foi compreendida. Isto deve-se ao facto de a versão 10.15.1 do [node.js] utilizada neste curso (setembro de 2019) ainda não estar em conformidade com a norma ECMAScript para a importação de pacotes denominados módulos. Em 2019, o [node.js] cumpre uma norma de módulos denominada CommonJS. A integração dos módulos ECMAScript pelo [node.js] está prevista para 2020. Mais uma vez, os programadores puseram mãos à obra e criaram pacotes que permitem a utilização dos módulos ES6 com o [node.js] já a partir de agora (2019).

Vamos utilizar um pacote chamado [esm] (Módulos ECMAScript). Instalamo-lo num terminal do projeto [javascript]:

Image

No [4], verifica-se que a instalação do pacote [esm] [1-3] alterou o ficheiro [javascript/package.json].

Ainda não terminámos. Para que o módulo [esm] seja utilizado pelo [node.js], é necessário executá-lo com o argumento [-r esm].

Por isso, alteramos a configuração da extensão [Code Runner] do [VSCode]:

Image

Image

Na extensão [11], adicionamos o argumento [-r esm] e guardamos (Ctrl-S) a configuração.

Agora, podemos executar o script [str-04]:


'use strict';
// utilização de um pacote externo para aceder à função sprintf
import { sprintf } from 'sprintf-js';
// cadeia
const chaîne = "Introduction à Javascript par l'exemple";
// método substr
console.log(sprintf("[%s].substr(3,2)=[%s]", chaîne, chaîne.substr(3, 2)));

Image

6.5. script [str-05]

Eis o que diz a documentação sobre a função [sprintf]:

Os marcadores de posição na cadeia de formato são assinalados por % e são seguidos por um ou mais destes elementos, nesta ordem:

  • Um número opcional seguido do símbolo $, que seleciona o índice do argumento a utilizar para o valor. Se não for especificado, os argumentos serão colocados na mesma ordem que os marcadores de posição na cadeia de caracteres de entrada.
  • Um sinal + opcional que obriga a preceder o resultado com um sinal de mais ou de menos nos valores numéricos. Por predefinição, apenas o sinal - é utilizado em números negativos.
  • Um especificador de preenchimento opcional que indica qual o carácter a utilizar para o preenchimento (se especificado). Os valores possíveis são 0 ou qualquer outro carácter precedido por uma ' (aspas simples). Por predefinição, o preenchimento é feito com espaços.
  • Um sinal de «-» opcional, que faz com que o `sprintf` alinhe à esquerda o resultado deste marcador de posição. Por predefinição, o resultado é alinhado à direita.
  • Um número opcional que indica quantos caracteres o resultado deve ter. Se o valor a ser devolvido for mais curto do que este número, o resultado será preenchido. Quando utilizado com o especificador de tipo j (JSON), o comprimento de preenchimento especifica o tamanho da tabulação utilizada para o recuo.
  • Um modificador de precisão opcional, composto por um . (ponto) seguido de um número, que indica quantos dígitos devem ser exibidos para números de ponto flutuante. Quando utilizado com o especificador de tipo g, especifica o número de dígitos significativos. Quando utilizado numa cadeia de caracteres, faz com que o resultado seja truncado.
  • Um especificador de tipo que pode ser qualquer um dos seguintes:
    • % — produz um carácter % literal
    • b — produz um inteiro como número binário
    • c — produz um inteiro como o carácter com esse valor ASCII
    • d ou i — produz um inteiro como um número decimal com sinal
    • e — produz um número de precisão flutuante utilizando notação científica
    • u — retorna um inteiro como um número decimal sem sinal
    • f — devolve um valor de tipo float tal como está; ver notas sobre precisão acima
    • g — produz um valor de tipo float tal como está; ver notas sobre precisão acima
    • o — produz um inteiro na forma octal
    • s — devolve uma cadeia de caracteres tal como está
    • t — retorna «true» ou «false»
    • T — devolve o tipo do argumento1
    • v — devolve o valor primitivo do argumento especificado
    • x — devolve um número inteiro como número hexadecimal (em minúsculas)
    • X — devolve um inteiro como um número hexadecimal (em maiúsculas)
    • j — devolve um objeto ou matriz JavaScript como uma cadeia de caracteres codificada em JSON

O script [script-05] implementa alguns destes formatos:


'use strict';
// utilização de um pacote externo para aceder à função sprintf
import { sprintf } from 'sprintf-js';
// cadeia
const chaîne = "Javascript";
// cadeias de caracteres
console.log(sprintf("[%s, %%s]=>[%s]", chaîne, chaîne));
console.log(sprintf("[%s, %%20s]=>[%20s]", chaîne, chaîne));
console.log(sprintf("[%s, %%-20s]=>[%-20s]", chaîne, chaîne));
// inteiros
console.log(sprintf("[%d, %%d]=>[%d]", 10, 10));
console.log(sprintf("[%d, %%4d]=>[%4d]", 10, 10));
console.log(sprintf("[%d, %%-4d]=>[%-4d]", 10, 10));
console.log(sprintf("[%d, %%04d]=>[%04d]", 10, 10));
// números reais
console.log(sprintf("[%f, %%f]=>[%f]", -10.5, -10.5));
console.log(sprintf("[%f, %%10.2f]=>[%10.2f]", -10.5, -10.5));
console.log(sprintf("[%f, %%-10.2f]=>[%-10.2f]", -10.5, -10.5));
console.log(sprintf("[%f, %%010.3f]=>[%010.3f]", -10.5, -10.5));
// json
console.log(sprintf("personne (%%j)=%j", { nom: "mathieu", âge: 34 }));
// tipo
console.log(sprintf("type personne (%%T)=%T", { nom: "mathieu", âge: 34 }));
// booleano
console.log(sprintf("booléen (%%t)=%t", 4 === 4));

Execução


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\strings\str-05.js"
[Javascript, %s]=>[Javascript]
[Javascript, %20s]=>[ Javascript]
[Javascript, %-20s]=>[Javascript ]
[10, %d]=>[10]
[10, %4d]=>[ 10]
[10, %-4d]=>[10 ]
[10, %04d]=>[0010]
[-10.5, %f]=>[-10.5]
[-10.5, %10.2f]=>[ -10.50]
[-10.5, %-10.2f]=>[-10.50 ]
[-10.5, %010.3f]=>[-00010.500]
personne (%j)={"nom":"mathieu","âge":34}
type personne (%T)=object
booléen (%t)=true

6.6. script [str-06]

O script [str-06] apresenta alguns métodos da classe [String] que também podem ser utilizados no tipo [string]:


'use strict';
// utilização de um pacote externo para dispor da função sprintf
import { sprintf } from 'sprintf-js';
// cadeia
const chaîne = "  Introduction à Javascript ";
// alguns métodos
// substr(10,2): 2 caracteres a partir do n.º 10
console.log(sprintf("[%s].substr(10,2)=[%s]", chaîne, chaîne.substr(10, 2)));
// trim: remoção de espaços em branco no início e no fim da cadeia (espaço em branco = \b \t \r \n \f)
console.log(sprintf("[%s].trim()=[%s]", chaîne, chaîne.trim()));
// toLowerCase: conversão para minúsculas
console.log(sprintf("[%s].toLowerCase=[%s]", chaîne, chaîne.toLowerCase()));
// toUpperCase: conversão para maiúsculas
console.log(sprintf("[%s].toUpperCase=[%s]", chaîne, chaîne.toUpperCase()));
// indexOf: posição de uma cadeia d e caracteres procurada na cadeia, -1 se a subcadeia não existir
console.log(sprintf("[%s].indexOf('Java')=[%s]", chaîne, chaîne.indexOf('Java')));
console.log(sprintf("[%s].trim().indexOf('abcd')=[%s]", chaîne, chaîne.indexOf('abcd')));
// includes: verdadeiro se a cadeia procurada estiver na cadeia
console.log(sprintf("[%s].includes('Java')=[%s]", chaîne, chaîne.includes('Java')));
// length: comprimento da cadeia de caracteres — não é um método, mas sim uma propriedade
console.log(sprintf("[%s].length=[%s]", chaîne, chaîne.length));
// slice (7,10): subcadeia dos caracteres n.º 7 a 9
console.log(sprintf("[%s].slice(7,10)=[%s]", chaîne, chaîne.slice(7, 10)));
// match: procura uma expressão na cadeia de caracteres — esta expressão pode ser uma expressão regular
// /intro/i: expressão regular que designa a cadeia [intro] em maiúsculas ou minúsculas
// retorna a cadeia encontrada
console.log(sprintf("[%s].match(/intro/i)=[%s]", chaîne, chaîne.match(/intro/i)));
// substituir: substitui a cadeia1 pela cadeia2 na cadeia
// substitui a primeira ocorrência de i por x
console.log(sprintf("[%s].replace('i','x')=[%s]", chaîne, chaîne.replace('i', 'x')));
// substitui todas as ocorrências de i por x
// /i/g é uma expressão regular que designa todas (g) as ocorrências de i
console.log(sprintf("[%s].replace(/i/g,'x')=[%s]", chaîne, chaîne.replace(/i/g, 'x')));
// split: divide a cadeia em palavras separadas pelo parâmetro de divisão
// retorna o array com essas palavras
// /\s*/: palavras separadas por 0 ou mais espaços
console.log(sprintf("[%s].split(/\\s*/)=[%s]", chaîne, chaîne.split(/\s*/)));
// /\s+/: palavras separadas por um ou mais espaços
console.log(sprintf("[%s].split(/\\s+/)=[%s]", chaîne, chaîne.split(/\s+/)));

Execução


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\strings\str-06.js"
[ Introduction à Javascript ].substr(10,2)=[ti]
[ Introduction à Javascript ].trim()=[Introduction à Javascript]
[ Introduction à Javascript ].toLowerCase=[ introduction à javascript ]
[ Introduction à Javascript ].toUpperCase=[ INTRODUCTION À JAVASCRIPT ]
[ Introduction à Javascript ].indexOf('Java')=[17]
[ Introduction à Javascript ].trim().indexOf('abcd')=[-1]
[ Introduction à Javascript ].includes('Java')=[true]
[ Introduction à Javascript ].length=[28]
[ Introduction à Javascript ].slice(7,10)=[duc]
[ Introduction à Javascript ].match(/intro/i)=[Intro]
[ Introduction à Javascript ].replace('i','x')=[ Introductxon à Javascript ]
[ Introduction à Javascript ].replace(/i/g,'x')=[ Introductxon à Javascrxpt ]
[ Introduction à Javascript ].split(/\s*/)=[,I,n,t,r,o,d,u,c,t,i,o,n,à,J,a,v,a,s,c,r,i,p,t,]
[ Introduction à Javascript ].split(/\s+/)=[,Introduction,à,Javascript,]