Pawn Strings.
Por rjjj ou Ken
Por rjjj ou Ken
Em programação, string é a denominação de uma sequência de caracteres (letras, números, símbolos). Ela, quando em um código, pode ser encontrada na forma de uma palavra, de uma frase ou até de um texto .
O objetivo da utilização de strings é basicamente a elaboração de expressões que venham a ter um significado em algum momento da execução do programa.
Nem toda letra de um código-fonte é necessariamente parte de uma string. Na linha abaixo por exemplo, o trechoSendClientMessageToAll, por mais que seja um sequência de caracteres, não é uma string :
Code:
SendClientMessageToAll(0xFFFFFFAA, "Oi");
Porém o trecho "Oi" é, devido à equivalência que há entre o mesmo e uma palavra durante a leitura do código, diferentemente deSendClientMessageToAll, que por sua vez tem o papel de adicionar mensagens ao chat de todos os jogadores.
1 - Declaração.
Em Pawn, pode-se declarar uma string de duas maneiras .
A primeira é através da delimitação com aspas (" ") do que desejamos que seja uma string:
Code:
"Sou uma string"
A segunda é a inserção do operador de stringizing (#) na frente do que será a string:
Code:
#Sou uma string
Também é possível fazer isso através do preenchimento de uma variável array com certos valores e através de funções como strcat, mas esse já é um tipo mais implícito de declaração.
2 - Armazenamento.
Para que uma string seja processada ela precisa estar armazenada em uma variável array .
As seguintes sentenças expressam as relações existentes entre uma string e a array que a contém:
Code:
Se uma string está contida em uma variável array, cada caractere da string está contido em uma parte da array.
Se uma variável array tem tamanho igual a x ela poderá armazenar uma string de no máximo (x - 1) caracteres.
Essa última sentença pode ser explicada pelo fato de as strings sempre terminarem com um caractere especial chamado EOS (acrônimo para "End Of String", fim de string em inglês), que na prática não é um caractere integrante.
Exemplos:
Code:
new x[3] = "AB"; //A variável array x armazena a string "AB".
new y[4] = #lol; //A variável array y armazena a string "lol".
new z[4] = "mano"; //A variável array z armazena a string "mano" (?).
É comum pensar que todos os códigos acima estão corretos, mas não estão .
No último caso tenta-se armazenar uma string de 4 caracteres em uma variável array de tamanho 4, o que desobedece uma das regras que citei no início desta seção do tutorial.
Para evitar ter que saber o total de caracteres da string para designar o tamanho da variável array que a conterá, pode-se utilizar o seguinte truque:
Code:
new Var[] = "Pawn";
Deixando os colchetes ([ ]) vazios, o tamanho da array será calculado automaticamente durante a compilação. Isso só funciona quando a string a ser armazenada for igualada à variável durante sua inicialização.
Em outros casos será necessário colocar nos colchetes um número grande o suficiente para permitir o armazenamento de qualquer uma das strings que possam vir.
Quando criamos uma variável array sem especificar os elementos que a mesma conterá, esses valores acabam sendo zeros. Como o valor de EOS é zero, uma variável como essa armazena um tipo de string, a de tamanho nulo:
Code:
new x[10] = ""; //A variável array x contém a string de tamanho nulo.
new y[10]; //A variável y também contém a string de tamanho nulo.
3 - Composição.
Code:
new pow[7] = "número";
A variável array do código acima tem esta composição :
Code:
pow[0] contém o caractere n.
pow[1] contém o caractere ú.
pow[2] contém o caractere m.
pow[3] contém o caractere e.
pow[4] contém o caractere r.
pow[5] contém o caractere o.
pow[6] contém o caractere EOS.
Note que os caracteres da string interna ficam ordenados. Graças a isso é possível executar um loop que substitua, em uma string, o caractere o pelo a, por exemplo.
Usando o exemplo da string em pow, se eu quisesse transformar "número" em "númera", faria isto:
Code:
pow[5] = 'a';
Quando queremos trabalhar com um caractere individualmente como no caso acima, delimitamos o mesmo com apóstrofos (' ').
Obteríamos o mesmo resultado se tivéssemos feito isto:
Code:
pow[5] = 97;
Mas por quê ?
Porque números e caracteres de strings estão associados de acordo com a tabela de símbolos ASCII.
Por esse motivo sempre poderemos construir uma string apenas com números:
Code:
new o[3] = {97, 102, 0};
//É o mesmo que:
new o[3] = {'a', 'f', '\0'};
//Que é o mesmo que:
new o[3] = "af";
4 - Packed Strings.
Quando uma variável é declarada no código Pawn a mesma é destinada a ocupar uma parte da memória do computador durante o processamento do arquivo .amx (resultado da compilação) .
O elemento correspondente a uma variável scalar (não-array) na memória chama-se cell, e tem um tamanho de 4 bytes (32 bits).
Como variáveis arrays são estruturas de dados elas podem originar várias cells. A quantidade dessas cells é igual ao número que é colocado dentro do par de colchetes ([ ]) ao lado do nome da variável array, na criação da mesma .
Quando a array é multidimensional o total de cells que serão originadas é igual ao produto dos valores dentro dos pares de colchetes.
Exemplo:
Code:
new Circulo; //Essa variável originará 1 cell.
new Quadrado[3]; //Essa variável originará 3 cells.
new Triangulo[10][20]; //Essa variável originará 200 cells.
Como vimos anteriormente quando uma string está armazenada em uma variável array, cada caractere da mesma, contando com o EOS, fica em uma parte da array.
Um caractere ASCII sempre terá um tamanho de no máximo 1 byte (8 bits) devido à constituição binária dos números que são equivalentes a eles (0 a 255).
Então, se uma parte de uma variável array tem tamanho de 4 bytes e um caractere de 1 byte, quando uma string é formada, 3 bytes por caractere ficam inutilizados.
E é aí que entram as packed strings, que são strings em que cada caractere ocupa 1 byte, ou seja, 1/4 de uma parte da array.
Para declarar uma packed string basta colocar o símbolo ! na frente da string:
Code:
new STR[4] = !"Packed string";
A string acima, contando com o EOS, contém 14 caracteres.
Então a variável array STR deveria ter um tamanho de no mínimo 14 bytes.
Como cada parte de array tem tamanho de 4 bytes, é impossível criar uma array de apenas 14 bytes, por isso escolhemos o menor tamanho possível, 16 bytes (4 cells) .
No fim acabamos armazenando uma string de 13 caracteres em uma array de tamanho 4.
Para trabalhar com um caractere de uma packed string em particular fazemos o seguinte:
Code:
new PKD[1] = !"Oie";
printf("%c", PKD{0}); //Mostraria o caractere O.
printf("%c", PKD{1}); //Mostraria o caractere i.
printf("%c", PKD{2}); //Mostraria o caractere e.
PKD{0} = 'A'; //Trocaria o caractere O pelo A, na string.
print(PKD); //Imprime a packed string "Aie".
//Obs: PKD{3} conteria o EOS.
Obs: Uma cell do SA-MP Pawn tem um tamanho fixo de 32 bits.
Poucas funções que trabalham somente com strings suportam packed strings (como strpack e strunpack, que convertem uma string para packed string e vice-versa), o que é um dos motivos desse recurso ser raramente usado.
5 - Manipulação.
Nessa parte do tutorial explicarei as técnicas de manipulação de strings :
* Concatenação
Concatenação é a união de strings baseada na junção do fim de uma com o início de outra.
Para realizar esse processo durante a inicialização da variável array que armazenará a string resultante pode-se colocar as strings a serem unidas uma ao lado da outra :
Code:
new Array[] = "SA-MP" "Fórum"; //Seria o mesmo que colocar "SA-MP Fórum".
Quando as strings estão em arrays, deve-se usar a função strcat, que significa "string concatenation" (ou "string concatenate"), concatenação de strings em inglês:
Exemplo:
Code:
new Pawn[20] = "Script";
strcat(Pawn, "ing"); //Concatena a string na variável Pawn e a string "ing".
print(Pawn); //Mostra a string "Scripting".
* Inserção
Na inserção de strings, uma string é inserida em outra.
Durante a inicialização da array que conterá a string final, podemos fazer isto, por exemplo, para inserir a substring (string interna) "está" na string "Onde esse indivíduo ?":
Code:
new Exemplo[] = "Onde" "está" "esse indivíduo ?";
A função desenvolvida para inserir strings em outras é o strins, que significa "string insertion" (ou "string insert"), inserção de strings em inglês:
Exemplo:
Code:
new Pawn[20] = "É ing";
strins(Pawn, "script", 2); //Insere a string "script" de modo que o primeiro caractere dela passe a ocupar Pawn[2].
print(Pawn); //Mostra a string "É scripting".
* Deleção
Na deleção de strings, parte de uma string é removida.
Quando conhecemos a string em detalhes, podemos apenas apagá-la, obviamente.
Mas quando não sabemos podemos utilizar esta propriedade se o que se quiser for apenas remover caracteres a partir do começo da string :
Code:
Se uma string x está armazenada em uma variável array y, o dado y[z], se considerado string, será igual à x sem os z primeiros caracteres.
Exemplo:
Code:
new Config[20] = "Settings";
print(Config[2]); //Mostra a string "ttings".
Caso contrário utilizamos a função strdel, que é "string deletion" (ou "string delete"), deleção de strings em inglês. Ela é de "propósito geral" no campo da deleção de strings:
Exemplo:
Code:
new Letras[5] = "ABCD";
strdel(Letras, 1, 3); //Apaga os caracteres em Letras[1] e Letras[2], ignorando o em Letras[3] para frente.
print(Letras); //Mostra a string "AD".
* Extração
Fazer a extração de uma string é, como o nome diz, obter uma substring de uma string.
Quando a string não está armazenada em uma array, basta copiar uma parte dela .
Mas quando está, aplicamos a função strmid, que significa "string middle", "metade de string" em inglês, uma referência à capacidade da mesma.
Exemplo:
Code:
new Tipo[6] = "MySQL";
new Linguagem[4];
strmid(Linguagem, Tipo, 2, 5); //Armazena na variável Linguagem a string formada por Tipo[2], Tipo[3] e Tipo[4], ignorando Tipo[5] para frente.
print(Linguagem); //Mostra a string "SQL".
* Comparação
Para comparar duas strings utilizamos a função strcmp, que significa "string comparison" (ou "string compare"), comparação de strings em inglês.
Essa função retorna o número zero se as strings passadas aos seus dois primeiros parâmetros forem iguais, e um número diferente de zero se forem diferentes:
Exemplo:
Code:
new A[6] = "Alpha";
new B[5] = "Beta";
if(strcmp(A, B) == 0) //Checa se as strings em A e B são iguais.
{
print("As variáveis A e B contêm a mesma string."); //Se forem, uma mensagem é exibida.
}
* Encontramento
Para facilitar a procura de uma string dentro de outra, a função strfind ("string find", encontrar string em inglês) foi desenvolvida.
Ela tenta encontrar a string passada ao seu segundo parâmetro dentro da string direcionada ao primeiro parâmetro. Retorna -1 se a string não tiver sido encontrada .
Exemplo:
Code:
new Nome[7] = "Ken_xD";
new Cla[3] = "xD";
if(strfind(Nome, Cla) != -1) //Checa se a string da variável Cla foi encontrada dentro da string da variável Nome.
{
print("Ken_xD é do clã xD."); //Se a string for encontrada, um mensagem é exibida.
}
* Tokenização
Tokenização é o processo de segmentação de uma string em outras menores, denominadas tokens.
Para executar uma tokenização podemos utilizar a função strtok, que significa "string tokenization" (ou "string tokenize"), tokenização de strings em inglês. Apesar de não ser uma função padrão, strtok vem definida em boa parte dos GMs que vêm com a pasta server do SA-MP .
Esse código porém, pelo menos na versão encontrada nesses GMs, considera como delimitador das substrings que serão tokens sempre o caractere ASCII 32 (espaço).
Exemplo:
Code:
new STR[] = "Groove domina o parque";
new Indice;
print(strtok(STR, Indice)); //Mostra a string "Groove".
print(strtok(STR, Indice)); //Mostra a string "domina".
print(strtok(STR, Indice)); //Mostra a string "o".
print(strtok(STR, Indice)); //Mostra a string "parque".
Para uma tokenização com qualquer delimitador, recomenda-se o plugin sscanf.
* Formatação
Bem, a formatação é flexível a ponto de substituir por exemplo strcat em um código.
Entretanto a função responsável por isso é mais lenta, por isso ás vezes pode não agradar aqueles que gostam de otimizar ao máximo .
Trata-se da função format.
Ao primeiro parâmetro do format deve-se passar a variável array na qual se quer armazenar a string formatada, ao segundo o número máximo de caracteres de string contando com o EOS que a array pode conter, e ao terceiro o formato de string a ser assumido.
Nesse terceiro parâmetro podem ser colocados símbolos chamados placeholders, que durante a execução do código, são substituídos ordenadamente pelos valores que são colocados na elipse no fim do format.
Os placeholders mais comuns são:
Code:
%s (é substituído por uma string).
%d ou %i (é substituído por um número inteiro).
%f (é substituído por um ponto flutuante, isto é, um número racional).
Exemplo:
Code:
new Tudo[23];
new Individuo[] = "O menino";
new Nota = 8;
format(Tudo, 23, "%s tirou nota %d", Individuo, Nota); //%s e %d são substituídos, nessa ordem, pelo conteúdo das variáveis Individuo e Nota.
print(Tudo); //Mostra a string "O menino tirou nota 8".
6 - Caractere de escape.
A barra invertida (\) não é um caractere comum, pois pode concatenar linhas de strings e de diretivas de pré-processador, além de permitir a participação de caracteres especiais em strings .
Por exemplo, não há nenhum símbolo que podemos colocar em strings para se referir ao caractere ASCII 7, que é não-imprimível.
Então utilizamos o chamado caractere de escape, a barra invertida:
Code:
print("A"); //Mostra o caractere ASCII 65.
print("\7"); //Mostra o caractere ASCII 7.
Como as aspas em Pawn servem para indicar strings e como a barra invertida é o próprio caractere de escape, estes precisam do caractere de escape para serem exibidos:
Code:
print("\""); //Mostra um dos símbolos de aspas.
print("\\"); //Mostra uma barra invertida.
Para escolher o caractere de escape, basta colocar o seguinte código no topo do GM:
Code:
#pragma ctrlchar 'x' //Troque x pelo novo caractere de escape.
Espero ter ajudado .
creditos: kenjj