Este é o comportamento esperado para String.containsOnly ()?

Sep 11 2020

Aqui está um código para ilustrar o problema.

String str1 = '';
System.debug(str1.containsOnly('W'));

Eu esperava falsecomo o resultado, mas surpreendentemente o resultado foi true. Não entendo por que esse é o caso, considerando que uma string vazia não contém um 'W'caractere. Este é um comportamento esperado ou um bug?

Edit : Depois das respostas que recebi até agora, acho que preciso reformular minha pergunta e torná-la mais fundamental. Ao fazer isso, a pergunta original será respondida.

Uma suposição subjacente que estou fazendo é que a documentação do método precedeu e foi a base da implementação do método e não vice-versa. Se você acha que essa suposição está errada, por favor me avise.

Deixando de lado como containsOnly()é implementado atualmente, como a documentação do método deve ser entendida? É mais uma questão de significado ou semântica do que técnica. Esta é a descrição fornecida.

containsOnly (inputString) Retorna verdadeiro se a String atual contiver caracteres apenas da seqüência de caracteres especificada e nenhum outro caractere; caso contrário, retorna falso.

Aqui estão as possíveis interpretações até agora:

  1. A string atual não contém nenhum caractere fora dos caracteres da string de entrada. (@PhilW)

  2. A string atual contém qualquer um dos caracteres da string de entrada ( containsAny(inputString)) && interpretação 1. (Meu entendimento).

Por favor, deixe-me saber como você entende a documentação ou a frase containsOnly e se você tiver outras interpretações plausíveis, irei adicioná-las à lista. Acho que algum consenso é necessário sobre isso antes de entrar na implementação real do método.

Respostas

8 PhilW Sep 11 2020 at 13:10

Logicamente, sim, porque a string vazia não contém nenhum caractere não permitido.

Caracteres não permitidos são quaisquer caracteres não listados explicitamente na especificação "apenas". Portanto, neste caso, é qualquer letra diferente de "W".

Se eu fosse implementar esse método sozinho, faria algo como:

public Boolean containsOnly(String allowed) {
    // "chars" is the internal array of characters in the string
    for (Integer i = 0; i < chars.size(); i++) {
        if (allowed.indexOfChar(chars[i]) < 0) {
            return false;
        }
    }

    return true;
}

O que quero dizer é que é uma iteração compacta procurando por caracteres não permitidos com saída antecipada conforme necessário e, se você não encontrar nenhum caractere não permitido, simplesmente retorne verdadeiro.

Não acho que esse comportamento possa ser considerado um bug; é o resultado natural da verificação de forma compacta e eficiente. Você também pode ver uma string vazia como nenhuma instância do caractere 'W'. String.containsOnlyretornará verdadeiro para:

  • zero caracteres 'W' (a string vazia)
  • um caractere 'W' (a string 'W')
  • dois caracteres 'W' (a string 'WW')
  • etc.

Se você deseja verificar se possui uma string não vazia e possui apenas os caracteres especificados, adapte seu código para fazer:

if (str1.isNotEmpty() && str1.containsOnly('W')) {
   ...
}
3 nbrown Sep 11 2020 at 21:43

Estou inclinado a pensar que isso não é um bug e é um comportamento padrão, mas a documentação é, na melhor das hipóteses, ambígua e não dá nenhuma indicação de como uma string vazia deve operar . Esclarecimento adicional é justificada dado que containse containsOnlyretornar resultados diferentes nesses cenários:

''.contains('W');     //false
''.containsOnly('W'); //true

Adendo : alguns exemplos adicionais que mostram como essa função é mais parecida com um conjunto do que containsquando procura uma substring em uma determinada string:

'abab'.containsOnly('ab');   //true
'ab'.containsOnly('abab');   //true
'abab'.containsOnly('abcd'); //true

'abab'.contains('ab');       //true
'ab'.contains('abab');       //false
'abab'.contains('abc');      //false

A containsOnlyoperação deve ser definida em termos matemáticos e tenho um palpite de que é implementada dessa forma. Não existe estritamente uma operação como containsOnly( que eu saiba - eu não sou um matemático ), mas você pode chegar lá de duas maneiras com operações de conjunto padrão. Se você pegar a interseção (∩) dos dois conjuntos e a interseção for a mesma do seu primeiro operando, é true, o que significa que os dois conjuntos se sobrepõem inteiramente:

{A, B} ∩ {A, B} = {A, B}

{} ∩ {A, B} = {}

Mas as regras da álgebra de conjuntos tratam um conjunto vazio de uma maneira única, de forma que todos os itens a seguir são equivalentes:

{} ∩ {A, B} ≡ {} ∩ {} ≡ {}

Isso explicaria por que uma string vazia, que é um 'conjunto' vazio de caracteres, sempre retornaria true quando a operação fosse realizada nela. A interseção do conjunto vazio com qualquer outro conjunto (incluindo outro conjunto vazio) é sempre o conjunto vazio.

Essa era uma maneira de implementar uma containsOnlyfunção usando operações de conjunto. A outra é usar a diferença (\). Se a diferença de dois conjuntos for a mesma do original, você poderia dizer que o primeiro conjunto contém apenas o segundo conjunto. Novamente, o conjunto vazio se comporta de maneira semelhante ao uso de uma interseção.

{A, B} \ {A} = {B}

{A, B} \ {A, B} = {} ≡ {} \ {A, B} = {} ≡ {} \ {} = {}

Minha suposição é que containsOnlyé implementado usando um desses métodos para seu algoritmo e a documentação para a Stringclasse precisa ser atualizada para refletir a metodologia atual do método (para que futuros desenvolvedores estejam cientes das nuances). Ou o método deve ser alterado para ser consistente contains.