Está aqui

atensão aos operadores == e != na jaws scripting language

por Marlon
Categoria do truque/dica:

Este documento se destina a pessoas que escrevem scripts para o jaws, ou para aqueles que estão aprendendo a fazê-lo.

Este documento irá:
- Apontar os problemas detectados;
- Mostrar a docummentação oficial para desenvolvedores da jaws scripting language;
- Mostrar como reproduzir os problemas apontados;
- Mostrar o modo de solucioná-los.

Problema: Os operadores == (igual igual) e != (exclamação igual) têm um comportamento diferente do descrito pela documentação da jaws scripting language.
Abaixo a documentação em inglês, a documentação traduzida e procedimentos para testar as divergências entre o comportamento dos operadores e sua documentação.

operador !=

Documentação original:
The != (exclamation mark equal to) operator asks whether the first condition is not equal to the second condition.

Documentação traduzida:
o operador != (sinal de exclamação sinal de igualdade) verifica se a primeira condição é não igual a segunda.

Uma condição pode ser o resultado de uma expressão, uma variável ou uma chamada de função.

Reprodução do problema:

Para reproduzir esse problema, faça o seguinte:

1- Crie um script chamado tst e associe uma tecla qualquer a ele
2- Escreva o seguinte texto:

if("mar" != "martelada") then
; se string "mar" for diferente da string "martelada"
sayString("diferentes")
else
; se forem iguais
sayString("iguais")
endIf

3- Compile o script

Executando-se esse script, o resultado é "iguais".

operador ==

Documentação original:
The == (equal equal) operator asks whether the first condition is equal to the second condition.

Documentação traduzida:
O operador == (sinal de igualdade sinal de igualdade) verifica se a primeira condição é igual a segunda condição

Uma condição pode ser o resultado de uma expressão, uma variável ou uma chamada de função.

Reprodução do problema

Para reproduzir esse problema,faça o seguinte:

1- Crie um script chamado tst e associe uma tecla qualquer a ele
2- Escreva o seguinte texto:

if("mar" == "martelada") then
; se string "mar" for igual a string "martelada"
sayString("iguais")
else
; se forem diferentes
sayString("diferentes")
endIf

3- Compile o script

Executando-se esse script, o resultado é "iguais".

Solução

Como é claramente notado os operadores == e != falham ao comparar duas strings.

O que torna esta questão ainda mais confusa, é que o compilador não reporta um erro se um dos dois operadores em questão for usado em operação com strings. Em vez disso, uma comparação em cima de uma regra arbitrária, não documentada, é silenciosamente realizada, podendo fazer com que diversos testes em scripts tenham um comportamento imprevisível, tornando complexo o processo de debug deste.
Por exemplo, se você precisar descobrir se a classe de uma janela é igual a uma determinada string, faria algo como (assumindo que o handle da janela esteja contido na variável win):

if(getWindowClass(win) == "CSListView") then
;alguma ação para tratar janelas da classe CSListView
endIf

Este código será executado quando:
1- A Classe da janela for igual a "CSListView" (operação desejada);
2- A classe da janela for "CSList" (possível bug);
3- A classe da janela for "CSL" (possível bug).

A regra que os operadores em questão usam para comparar strings é a seguinte:

- Operador ==

Compara, começando a partir do primeiro caracter a esquerda da string, um por um dos caracteres da string a esquerda do operador com o caracter da mesma posição na string a direita do operador, sem diferensiar maiúsculas e minúsculas, até que uma das duas strings terminem.
Se uma diferença é encontrada, retorna falso (as sstrings são não iguais) imediatamente. Se uma das strings terminar e nenhuma diferença for encontrada, retorna verdadeiro (as strings são iguais) independentemente dos caracteres restantes na outra string.
O fluxo da comparação seria mais ou menos esse:
Compara o primeiro caracter da string a esquerda do operador com o primeiro caracter da string a direita do operador.
Se forem diferentes retorna falso (strings não são iguais)
Se forem iguais, compara o segundo caracter da string a esquerda do operador com o segundo caracter da string a direita do operador.
Se forem diferentes retorna falso (strings não são iguais)
Se forem iguais, compara o terseiro caracter da string a esquerda do operador com o terseiro caracter da string a direita do operador, e assim sussessivamente.

Desta forma, segundo o operador:
listview é igual a list;
listview é igual a li;
listview é igual a listviewc;

O operador != trabalha da mesma forma, porém retorna verdadeiro (as strings são diferentes) se um dos caracteres da string a esquerda do operador for diferente do caracter na mesma posição da string a direita do operador. Se uma das strings terminar e não tiver sido localizado nenhum caracter diferente do seu correspondente na outra, retorna falso (as strings não são diferentes).

Esta regra pode parecer cconfusa, e realmente pode deixar programadores que não saibam de sua existência bastante confusos, pelas razões descritas acima.

No jaws 6.10 e superiores existe a função stringCompare, que fará uma comparação correta de strings. Mas mesmo nessas versões a documentação para os dois operadores em questão não deixa claro que eles fazem uma comparação que não segue o comportamento padrão quando lidando com strings, e mostrar esta regra.

Usar esta função para fazer comparação de strings irá resolver o problema, mas fará com que os scripts desenvolvidos só sejam aceitos no jaws versão 6.10 ou superior. Uma solução mais portável, uma vez que versões anteriores do jaws também apresentam esse comportamento nos operadores em questão, é escrever uma função própria para comparação de strings. O pessoal da list sobre jaws scripting, da blindprogramming.com, ajudou bastante nessa etapa (obrigado a Doug Lee).
include "hjconst.jsh" ; para definições de false e true, além de outras coisas
int function pStringCompare(string s1, string s2, int considerCase)
;Sabemos que para duas strings serem iguais
; - o tamanho delas precisa ser igual. Portanto, se o tamanho for
;diferente, retornamos falso.
; Além do tamanho ser igual, uma string precisa conter a outra. A
;função usada para determinar se uma string está contida em outra é ;stringContains, que diferencia entre maiúsculas e minúsculas.
; ela retorna verdadeiro se todos os caracteres de uma string estiverem
;dentro de outra, na mesma ordem em que foram especificados, e seguindo
;as variações de maiúsculas e minúsculas
if(stringLength(s1) != stringLength(s2)) then
; Tamanhho das duas strings diferente
return false
; Se o tamanho das duas strings for 0, ou seja, for passado "" para os
;dois parâmetros da função, talvez strContains retorne falso.
; Nos meus tests isso não aconteceu, mas é melhor codificar a função do
;modo mais seguro.
elif(!stringLength(s1)) then
; O tamanho de s1 é 0, logo o de s2 também é 0. Dessa forma, as duas ;strings são iguais
return true
endIf
; Se o código chegou até aqui, quer dizer que s1 e s2 têm o mesmo
;tamanho, e que o tamanho não é 0. Agora precisamos decidir se
;iremos diferenciar maiúsculas e minúsculas.
if(considerCase) then
; ConsiderCase recebeu o valor true, então só precisamos chamar
;strContains e retornar o que ela resultou
return stringContains(s1, s2)
else
; Precisamos passar todos os caracteres maiúsculos das duas strings
;para minúsculos, já que queremos que strContains retorne verdadeiro se
;as duas strings forem iguais independentemente disso
return stringContains(stringLower(s1), stringLower(s2))
endIf
endFunction

Os peradores em questão hajem rigorosamente como documentados quando fazendo comparações de tipo int e de tipo handle.

Escrevi este documento porque eu mesmo me perdi bastante nos meus scripts, até imaginar que esse era o problema. Quando perguntei a escritores de scripts mais experientes, fiquei atônito ao saber que este é um problema já bem conhecido. Se os operadores em questão realmente têm essa finalidade, isso deveria estar documentado, para que programadores não se confundam.

Uma das melhores características do jaws, e a que o torna o melhor leitor de telas existente hoje, é sua linguagem de scripts que faz com que o leitor opere de maneira muito extensível dentro do seu ambiente. Creio que quanto mais pessoas souberem escrever scripts para o jaws mais aplicações serão acessíveis, e em um tempo mais curto. Dessa forma, trarei dicas sobre a linguagem sempre que possível, já que a documentação (já rara em inglês) praticamente é nula em português.
Marlon