Página 1 de 1

Ascan ?

Enviado: 23 Abr 2011 13:36
por MARCELOG
Olá pessoal,
deparei-me com uma situação interessante.
Vejam isto:

aMatriz := {'a','b','c'}

? ascan(aMatriz,'b') // Retorna 2 Ok

? ascan(aMatriz,'') // Retorna 1 - ERRO

O comportamento relativo à segunda pesquisa está correto? Por quê?

MarceloG

:-o

Re: Ascan ?

Enviado: 23 Abr 2011 13:59
por sygecom
Olá Marcelo,
Estranho esse comportamento, aqui retorna 0(ZERO). Uso xHarbour 1.2.1 + Bcc5.5.1. Testou em outra maquina( isso não deveria mudar) ? Testou com outro compilador ?

Ascan ?

Enviado: 23 Abr 2011 16:19
por Pablo César
Eu testei Harbour + MiniGui (HMG) e obtive o mesmo resultado, isto é 1 para busca caracter vazio. Mas daí fiz este outro teste e observe:

Código: Selecionar todos

Function Main
aMatriz := {0,'b','c'}

? ascan(aMatriz,'b') // Retorna 2 Ok

? ascan(aMatriz,"") // Retorna 2 - Ok

? ascan(aMatriz,'d') // Retorna 0 - Ok
inkey(0)
Return
Que, mesmo que nos pareça esquisito, está correto, pois a pesquisa neste exemplo, denota que na verdade procura algum caracter (claro que eneste caso vazio) e que na verdade não deixa de estar acertado, pois o primeiro elemento é do tipo numérico. No entanto a terceira pesquisa ele retorna zero, pois nenhum elemento satisfaz a condição. Contudo, acho muito essa situação interessante, pois isso serve de alerta para os mais desavisados.

Re: Ascan ?

Enviado: 23 Abr 2011 20:37
por sygecom
Pablo, você testou apenas usando Harbour em modo console ?
Tem coisa errada, retornar 1 no meu ver está errado.

Re: Ascan ?

Enviado: 23 Abr 2011 21:01
por Maligno
O comportamento da função AScan() em Clipper, e usando a matriz que o Marcelo postou, é exatamente o mesmo. É erro? Sim e não. Se a matriz contém {'a','b','c'} e a busca por "" (NULO) retorna 1, não se pode dizer que está errado. Pode-se entender que ele retornou o primeiro elemento que contém o NULO. Como toda string sempre contém NULO, retorna 1. Na matriz do Pablo o primeiro elemento é numérico. Logo, o primeiro elemento que contém NULO é o segundo na seqüência; primeira string a aparecer. Normal. Se não é esse o comportamento que se espera, parece erro. Mas, de fato, não se pode dizer que seja.

De qualquer forma, a solução é simples. Basta usar AScan() com um bloco de código e testar pela nulidade do elemento. O código abaixo, que procura por NULO, retorna 0 para as duas matrizes dos exemplos.

Código: Selecionar todos

? AScan(aMatriz,{|x|valtype(x)="C" .and. x != ""})
O primeiro teste no bloco é necessário porque a matriz do Pablo mistura tipos. Sem esse teste tem-se erro de run-time.

Re: Ascan ?

Enviado: 24 Abr 2011 12:15
por MARCELOG
Olá pessoal,
obrigado por responderem.
Mas vejam bem, eu não estou procurando caracteres nulos na string, mas se a entrada existe na matriz é igual a nulo.
Então, considerando o que o Maligno falou é erro e deve ser reportado.

MarceloG

Re: Ascan ?

Enviado: 24 Abr 2011 16:22
por Maligno
Então o Clipper também está com esse bug esses anos todos? Não se pode classificar de bug só porque você não tem o que precisa. Não é bug. É só uma questão de implementação.

Mas pra resolver seu problema é fácil. Como eu disse, um bloco de código resolve. Se o que você quer é justamente saber se há uma string NULA, teste se ela está vazia com um bloco como o abaixo.

Código: Selecionar todos

AScan(aMatriz,{|x|Empty(x)})
ou
AScan(aMatriz,{|x|x==""})
ou
AScan(aMatriz,{|x|""=x})
Agora, se você não quer usar bloco de código também pode ser feito. Mas você precisará do SET EXACT ON. Aí pode usar a forma simples, como você fez antes.

Código: Selecionar todos

AScan(aMatriz,"")
Particularmente não gosto de resolver um problema desses com um SET, que é uma configuração global de sistema. Isso prejudica a abstração de qualquer função. Mas é fato: resolve também.

Re: Ascan ?

Enviado: 24 Abr 2011 18:37
por asimoes
Para ajudar a entender melhor o ascan, estou publicando a documentação da função.
Reparem o quinto parâmetro: lExact
AScan()
Searches a value in an array beginning with the first element.
Syntax
Ascan( <aArray> , ;
<xbSearch>, ;
[<nStart>], ;
[<nCount>], ;
[<lExact>], ;
[<lASCII>] ) --> nElement

Arguments
<aArray>
This is the array to iterate.
<xbSearch>
<xbSearch> is either the value to search in <aArray> or a code block containing the search condition. The code block receives a single parameter which is the value stored in the current array element. The code block must return a logical value. When the return value is .T. (true), the function stops searching and returns the position of the corresponding array element.
<nStart>
This is a numeric expression indicating the first element in the array to begin the search with. It defaults to 1, the first element of <aArray>.
<nCount>
A numeric expression specifying the number of elements to search. It defaults to 1+Len(<aArray>)-<nStart>.
<lExact>
This parameter influences the comparison for searching character strings in <aArray>. If .T. (true) is passed, an exact string comparison is performed. When omitted or if .F. (false) is passed, string comparison follows the SET EXACT rules.
<lASCII>
This parameter is only relevant for arrays that contain single characters in their elements. A single character is treated like a numeric ASCII value when <lASCII> is .T. (true). The default is.F. (false). Return
AScan() returns the numeric ordinal position of the array element that contains the searched value. When no match is found, the return value is 0.
Description
The array function AScan() traverses the array <aArray> for the value specified with <xbSearch>. If <xbSearch> is not a code block, AScan() compares the values of each array element for being equal with the searched value. If this comparison yields .T. (true), the function stops searching and returns the numeric position of the array element containing the searched value.
If a code block is passed for <xbSearch>, it is evaluated and receives as parameter the value of the current array element. The code block must contain a comparison rule that yields a logical value. AScan() considers the value as being found when the codeblock returns .T. (true). Otherwise the function proceeds with the next array element.
Note: use function RAscan() to search an array beginning with the last element.

Re: Ascan ?

Enviado: 24 Abr 2011 18:44
por asimoes
SET EXACT
Determines the mode for character string comparison.
Syntax
SET EXACT on | OFF | ( <lOnOff> )

Arguments
on | OFF | ( <lOnOff> )
This option toggles if an exact comparison is performed with character strings. or not. The default is OFF or .F. (false), i.e. characters are compared up the length of the shorter string. To change the setting use ON or .T. (true) as parameter. The parameter can also be specified as a logical expression enclosed in parentheses. Description
The SET EXACT command determines the mode for character string comparison with the comparison operators (=, >, <, =>, =<). The following rules are applied for comparison with SET EXACT set to ON:
1) When the right operand is a null string, the result is always .T. (true)

2) When the right operand is longer than the left operand, the result is always .F. (false)

3) When the right operand contains less or the same number of characters as the left operand, the result is only true if the left operand begins with the exact same characters as the right operand.

With SET EXACT set to OFF, the same rules apply except that trailing spaces are ignored in the comparison.
Notes: The exact equal operator == always performs an exact comparison irrespectively of the SET EXACT setting.
Search commands and functions such as SEEK, DbSeek() or SET RELATEION are not affected
Vejam a 3ª comparação no exemplo abaixo:

Código: Selecionar todos

PROCEDURE Main
      SET EXACT OFF
      ? "AB" = "ABCD"             // result: .F.
      ? "ABCD" = "AB"             // result: .T.
      ? "AB" = ""                 // result: .T.
      ? "" = "AB"                 // result: .F.
      ? "AB" = "AB  "             // result: .F.

      SET EXACT ON
      ? "AB" = "ABCD"             // result: .F.
      ? "ABCD" = "AB"             // result: .F.
      ? "AB" = ""                 // result: .F.
      ? "" = "AB"                 // result: .F.
      ? "AB" = "AB  "             // result: .T.

      ? "AB" == "AB  "            // result: .F.
   RETURN

Re: Ascan ?

Enviado: 24 Abr 2011 19:30
por Jairo Maia
Caros Colegas,

Também concordo com o Maligno, pois usar SET EXACT ON pode alterar outras pontos do mesmo aplicativo. Penso que para vc resolver o problema, uma vez que isso é necessario em seu projeto, vc deva substituir Ascan por RAscan:

aMatriz := {'a','b','c'}

? RAscan(aMatriz,'b') // Retorna 2 Ok

? RAscan(aMatriz,'') // Retorna 0 - Correto

Usnado Harbour 2.1 funcionou.

Re: Ascan ?

Enviado: 24 Abr 2011 20:04
por Maligno
Pra quem não conhece essa função (como eu - o Clipper não tem) poderia, por favor, descrever as diferenças entre AScan() e RAScan()? Da minha parte é só curiosidade. :)

Re: Ascan ?

Enviado: 24 Abr 2011 20:32
por fladimir
Olá pessoal, retirei do manual do xHarbour... segue sobre o RAScan()
RAscan()
Searches a value in an array beginning with the last element.
Syntax
RAscan( <aArray> , ;
<xbSearch>, ;
[<nStart>] , ;
[<nCount>] , ;
[<lExact>] , ;
[<lASCII>] ) --> nElement

Arguments
<aArray>
This is the array to iterate.
<xbSearch>
<xbSearch> is either the value to search in <aArray> or a code block containing the search condition. The code block receives a single parameter which is the value stored in the current array element. The code block must return a logical value. When the return value is .T. (true), the function stops searching and returns the position of the corresponding array element.
<nStart>
This is a numeric expression indicating the first element in the array to begin the search with. It defaults to Len(<aArray>), the last element of the array.
<nCount>
A numeric expression specifying the number of elements to search. It defaults to 1+Len(<aArray>)-<nStart>.
<lExact>
This parameter influences the comparison for searching character strings in <aArray>. If .T. (true) is passed, an exact string comparison is performed. When omitted or if .F. (false) is passed, string comparison follows the SET EXACT rules.
<lASCII>
This parameter is only relevant for arrays that contain single characters in their elements. A single character is treated like a numeric ASCII value when <lASCII> is .T. (true). The default is.F. (false). Return
RAScan() returns the numeric ordinal position of the array element that contains the searched value. When no match is found, the return value is 0.
Description
The array function RAscan() traverses the array <aArray> for the value specified with <xbSearch>. If <xbSearch> is not a code block, RAscan() compares the values of each array element for being equal with the searched value. If this comparison yields .T. (true), the function stops searching and returns the numeric position of the array element containing the searched value.
If a code block is passed for <xbSearch>, it is evaluated and receives as parameter the value of the current array element. The code block must contain a comparison rule that yields a logical value. AScan() considers the value as being found when the codeblock returns .T. (true). Otherwise the function proceeds with the next array element.
Note: use function AScan() to search an array beginning with the first element.
Info
See also: AEval(), Asc(), Ascan(), ASort(), ATail(), Eval(), IN, SET EXACT
Category: Array functions , xHarbour extensions
Source: vm\arrayshb.c
LIB: xhb.lib
DLL: xhbdll.dll
Example

Código: Selecionar todos

// The example demonstrates the difference between AScan() and RAscan().

   PROCEDURE Main()
      LOCAL aArray := { "A", 1, Date(), 1, .F. }

      ? Ascan( aArray, 1 )             // result: 2
      ? RAScan( aArray, 1 )            // result: 4

   RETURN


Re: Ascan ?

Enviado: 25 Abr 2011 09:38
por Jairo Maia
Olá pessoal,

Peço desculpas, as vezes "peco" pelo uso da síntese, e obrigado ao Fladimir que elucidou as dúvidas.

Resumindo, é uma junção da função RATE e ASCAN, e como explicado no texto postado pelo Fladimir, Ascan retorna o primeiro elemento, enquanto RAscan retorna o último.

Isso somente resolve se a idéia é saber se tal elemento está contido na matriz, sem importar a ordem. Caso contrário, deve-se usar Ascan. Se necessário, setar SET EXACT ON na mesma função que ira usar o Ascan (sem alterar a configuração global, como destacado pelo Maligno, e que é desaconselhável), onde situação identica a do Marcelo se fizer necessário.

Código: Selecionar todos

Func Main()
 Loca := aMatriz := {'a','b','c'}, lSetExac := SET(_SET_EXACT, .t. )

  ? ascan(aMatriz,'b') // Retorna 2

  ? ascan(aMatriz,'') // Retorna 0

  SET(_SET_EXACT, lSetExac)  // seta SET EXACT anterior

 Retu