Tipos de seqüências de caracteres no Groovy

Tipos de seqüências de caracteres no Groovy

1. Visão geral

Neste tutorial, examinaremos mais de perto os vários tipos de strings em https://www..com/groovy-language [Groovy], incluindo strings de aspas simples, aspas duplas, aspas triplas e slashy .

Também exploraremos o suporte de string do Groovy para caracteres especiais, multilinhas, regex, escape e interpolação de variáveis.

2. Aprimorando java.lang.String

Provavelmente é bom começar afirmando que, como o Groovy é baseado em Java, ele tem todos os recursos String do Java, como concatenação, a API String e os benefícios inerentes ao pool constante de String por causa disso.

Vamos primeiro ver como o Groovy estende alguns desses princípios.

2.1. Concatenação de String

A concatenação de strings é apenas uma combinação de duas strings:

def first = 'first'
def second = "second"
def concatenation = first + second
assertEquals('firstsecond', concatenation)

Onde Groovy se baseia nisso é com seus vários outros tipos de strings, os quais veremos em um momento. Observe que podemos concatenar cada tipo de forma intercambiável.

2.2. Interpolação de String

Agora, Java oferece alguns modelos muito básicos por meio de printf, mas o Groovy se aprofunda, oferecendo interpolação de cadeias * __, o processo de modelagem de cadeias com variáveis ​​*:

def name = "Kacper"
def result = "Hello ${name}!"
assertEquals("Hello Kacper!", result.toString())

Enquanto o Groovy suporta concatenação para todos os seus tipos de cadeias, ele fornece apenas interpolação para certos tipos.

2.3. GString

Mas escondido neste exemplo, há um pouco de rugas - por que estamos chamando _toString () _?

Na verdade, result_ não é do tipo String, mesmo que pareça.

Como a classe String é final, a classe de string do Groovy que suporta interpolação, GString, não a subclassifica. Em outras palavras, para o Groovy fornecer esse aprimoramento *, ele possui sua própria classe de string, GString, que não pode ser estendida de String . *

Simplificando, se o fizemos:

assertEquals("Hello Kacper!", result)

isso chama assertEquals (Object, Object), e obtemos:

java.lang.AssertionError: expected: java.lang.String<Hello Kacper!>
  but was: org.codehaus.groovy.runtime.GStringImpl<Hello Kacper!>
Expected :java.lang.String<Hello Kacper!>
Actual   :org.codehaus.groovy.runtime.GStringImpl<Hello Kacper!>

3. String com aspas simples

Provavelmente, a string mais simples do Groovy é uma com aspas simples:

def example = 'Hello world'

Sob o capô, esses são simplesmente Java Strings simples, e são úteis* quando precisamos ter aspas dentro da nossa string. *

Ao invés de:

def hardToRead = "Kacper loves \"Lord of the Rings\""

Podemos concatenar facilmente uma string com outra:

def easyToRead = 'Kacper loves "Lord of the Rings"'

Como podemos trocar tipos de cotação como esse, reduz a necessidade de escapar de cotações.

4. String tripla de aspas simples

*Uma cadeia tripla de aspas simples é útil no contexto de definição do conteúdo de várias linhas.*

Por exemplo, digamos que temos alguns JSON para representar como uma sequência:

{
    "name": "John",
    "age": 20,
    "birthDate": null
}
*Não precisamos recorrer à concatenação e a caracteres explícitos de nova linha para representar isso.*

Em vez disso, vamos usar uma cadeia tripla de aspas simples:

def jsonContent = '''
{
    "name": "John",
    "age": 20,
    "birthDate": null
}
  • O Groovy armazena isso como um simples Java String * e adiciona a concatenação e as novas linhas necessárias para nós.

Ainda há um desafio a ser superado.

*Normalmente, para facilitar a leitura do código, recuamos nosso código:*
def triple = '''
    firstline
    secondline

Mas cadeias triplas de aspas simples preservam espaços em branco . Isso significa que a string acima é realmente:

(newline)
    firstline(newline)
    secondline(newline)

not:

1

2

a

+ + + Primeira linha (nova linha) +

+ + + Segunda linha (nova linha) +

como talvez pretendêssemos.

Fique atento para ver como nos livramos deles.

4.1. Caractere de nova linha

Vamos confirmar que nossa string anterior começa com um caractere de nova linha :

assertTrue(triple.startsWith("\n"))

É possível tirar esse personagem. Para evitar isso, precisamos colocar uma única barra invertida _ \ _ como o primeiro e o último caractere:

def triple = '''\
    firstline
    secondline

Agora, pelo menos, temos:

1

2

a

+ + + Primeira linha (nova linha) +

+ + + Segunda linha (nova linha) +

Um problema resolvido, mais um por ir.

4.2. Retirar o recuo do código

Em seguida, vamos cuidar do recuo. Queremos manter nossa formatação, mas remover caracteres desnecessários de espaço em branco.

A API Groovy String vem em socorro!

*Para remover espaços à esquerda em todas as linhas de nossa string, podemos usar um dos métodos padrão do Groovy, _String # stripIndent () _:*
def triple = '''\
    firstline
    secondline'''.stripIndent()
assertEquals("firstline\nsecondline", triple)

Observe que, movendo os ticks para cima de uma linha, também removemos um caractere de nova linha à direita.

4.3. Recuo relativo

Devemos lembrar que stripIndent não é chamado stripWhitespace.

  • stripIndent determina a quantidade de recuo da linha reduzida de espaço em branco na cadeia.

Então, vamos mudar um pouco a indentação da nossa variável triple:

class TripleSingleQuotedString {

    @Test
    void 'triple single quoted with multiline string with last line with only whitespaces'() {
        def triple = '''\
            firstline
                secondline\
        '''.stripIndent()

       //... use triple
    }
}

Imprimir _ triplo_ nos mostraria:

firstline
    secondline
*Como __primeira linha __ é a linha que não é o espaço em branco menos recuada, ela fica com recuo zero com _secondline_ ainda recuado em relação a ela.*

Observe também que desta vez, estamos removendo o espaço em branco à direita com uma barra, como vimos anteriormente.

4.4. Tira com _stripMargin () _

*Para um controle ainda maior, podemos dizer ao Groovy exatamente onde iniciar a linha usando um | e _stripMargin _:*
def triple = '''\
    |firstline
    |secondline'''.stripMargin()

Qual seria exibido:

firstline
secondline
*O pipe indica onde a linha da string realmente começa.*

Além disso, podemos passar um Character ou CharSequence como argumento para stripMargin com nosso caractere delimitador personalizado.

Ótimo, nos livramos de todos os espaços em branco desnecessários, e nossa string contém apenas o que queremos!

4.5. Escapando caracteres especiais

*Com todas as vantagens da cadeia tripla de aspas simples, há uma consequência natural da necessidade de escapar aspas simples e barras invertidas que fazem parte da nossa cadeia.*

Para representar caracteres especiais, também precisamos escapar deles com uma barra invertida. Os caracteres especiais mais comuns são uma nova linha (_ \ n_) e tabulação (_ \ t_).

Por exemplo:

def specialCharacters = '''hello \'John\'. This is backslash - \\ \nSecond line starts here'''

vai resultar em:

hello 'John'. This is backslash - \
Second line starts here

É preciso lembrar alguns, a saber:

  • _ \ t _– tabulação

  • _ \ n_ - nova linha

  • _ \ b_ - backspace

  • _ \ r_ - retorno de carro

  • _ \\ _ - barra invertida

  • _ \ f_ - alimentação de formulário *\' - citação única

5. String com aspas duplas

Enquanto strings com aspas duplas também são apenas Java Strings, seu poder especial é a interpolação. Quando uma seqüência de caracteres entre aspas duplas contém caracteres de interpolação, o Groovy alterna o Java String para um GString.

====* 5.1. * GString e Lazy Evaluation

*Podemos interpolar uma string com aspas duplas cercando expressões com _ $ \ {} _ ou com _ $ _ para expressões pontilhadas.*
*Sua avaliação é lenta* , no entanto - ele não será convertido em um _String_ até que seja passado para um método que requer um _String_:
def string = "example"
def stringWithExpression = "example${2}"
assertTrue(string instanceof String)
assertTrue(stringWithExpression instanceof GString)
assertTrue(stringWithExpression.toString() instanceof String)

5.2. Marcador de posição com referência a uma variável

A primeira coisa que provavelmente queremos fazer com a interpolação é enviar uma referência variável:

def name = "John"
def helloName = "Hello $name!"
assertEquals("Hello John!", helloName.toString())

5.2. Espaço reservado com uma expressão

Mas também podemos dar expressões:

def result = "result is ${2 * 2}"
assertEquals("result is 4", result.toString())
*Podemos colocar até mesmo declarações em espaços reservados, mas isso é considerado uma má prática.*

5.3. Espaços reservados com o Operador de ponto

Podemos até andar hierarquias de objetos em nossas strings:

def person = [name: 'John']
def myNameIs = "I'm $person.name, and you?"
assertEquals("I'm John, and you?", myNameIs.toString())
*Com getters, o Groovy geralmente pode inferir o nome da propriedade.*
  • Mas se chamarmos um método diretamente, precisaremos usar _ $ \ {} _ * por causa dos parênteses:

def name = 'John'
def result = "Uppercase name: ${name.toUpperCase()}".toString()
assertEquals("Uppercase name: JOHN", result)

5.4. hashCode em GString e String

Strings interpoladas são certamente uma dádiva de Deus em comparação com java.util.String simples, mas* elas diferem de uma maneira importante. *

Veja, Java Strings são imutáveis ​​e, portanto, chamar hashCode em uma determinada string sempre retorna o mesmo valor.

Porém,* _ GString_ hashcodes podem variar *, pois a representação String depende dos valores interpolados.

  • E, na verdade, mesmo para a mesma sequência resultante, eles não terão os mesmos códigos de hash:

def string = "2+2 is 4"
def gstring = "2+2 is ${4}"
assertTrue(string.hashCode() != gstring.hashCode())
*Portanto, nunca devemos usar _GString_ como uma chave em um _Map _!*

6. String tripla de aspas duplas

Então, vimos cadeias de caracteres de aspas simples triplas e cadeias de aspas duplas.

Vamos combinar o poder de ambos para obter o melhor dos dois mundos - interpolação de cordas de várias linhas:

def name = "John"
def multiLine = """
    I'm $name.
    "This is quotation from 'War and Peace'"
"""

Além disso, observe que não tivemos que escapar de aspas simples ou duplas !

7. Slashy String

Agora, digamos que estamos fazendo algo com uma expressão regular e, portanto, estamos escapando de barras invertidas por todo o lugar:

def pattern = "\\d{1,3}\\s\\w+\\s\\w+\\\\\\w+"

Está claramente uma bagunça.

Para ajudar com isso, o Groovy suporta regex nativamente através de strings slashy:

def pattern =/\d{3}\s\w+\s\w+\\\w+/
assertTrue("3 Blind Mice\Men".matches(pattern))

Strings slashy podem ser interpolados e multilinhas :

def name = 'John'
def example =/
    Dear ([A-Z]+),
    Love, $name
/

Claro, temos que escapar de barras:

def pattern =/.*foobar.*\/hello.*/
  • E não podemos representar uma string vazia com Slashy String *, pois o compilador entende // como um comentário:

//if ('' ==//) {
//    println("I can't compile")
//}

8. Dólar-Slashy String

Cordas slashy são ótimas, embora seja uma chatice ter que escapar da barra. Para evitar o escape adicional de uma barra, podemos usar uma string com barra de dólar.

Vamos supor que temos um padrão regex: _ [0-3] +/[0-3] + _. É um bom candidato para uma string com barra de dólar porque, em uma string com barra, teríamos que escrever: _ [0-3] +//[0-3] + _.

As strings com barra de dólar * são GStrings multilinhas que abrem com $/e fecham com/$. *Para escapar de uma barra ou dólar, podemos precedê-la com o sinal de dólar ($), mas não é necessário.

Não precisamos escapar de $ no espaço reservado GString.

Por exemplo:

def name = "John"

def dollarSlashy = $/
    Hello $name!,

    I can show you a $ sign or an escaped dollar sign: $$
    Both slashes work: \ or/, but we can still escape it: $/

    We have to escape opening and closing delimiters:
    - $$$/
    - $/$$
/$

produziria:

Hello John!,

I can show you a $ sign or an escaped dollar sign: $
Both slashes work: \ or/, but we can still escape it:/

We have to escape opening and closing delimiter:
- $/
-/$

9. Personagem

Aqueles familiarizados com Java já se perguntaram o que o Groovy fez com os caracteres, pois usa aspas simples para strings.

Na verdade,* Groovy não possui um literal explícito de caracteres. *

Existem* três maneiras * de transformar uma string Groovy em um caractere real:

  • uso explícito da palavra-chave 'char' ao declarar uma variável

  • usando ‘como 'operador *transmitindo para ‘char '

Vamos dar uma olhada em todos eles:

char a = 'A'
char b = 'B' as char
char c = (char) 'C'
assertTrue(a instanceof Character)
assertTrue(b instanceof Character)
assertTrue(c instanceof Character)

A primeira maneira é muito conveniente quando queremos manter o caractere como uma variável. Os outros dois métodos são mais interessantes quando queremos passar um caractere como argumento para uma função.

===* 10. Resumo *

Obviamente, isso foi muito, então vamos resumir rapidamente alguns pontos-chave:

  • strings criadas com uma aspas simples (‘) não suportam interpolação

  • seqüências de caracteres de aspas duplas slashy e triplicadas podem ser multi-line

  • seqüências de várias linhas contêm caracteres de espaço em branco devido ao recuo do código

  • barra invertida (\) é usada para escapar de caracteres especiais em todos os tipos, exceto string com barra de dólar, onde devemos usar dollar ($) para escapar

11. Conclusão

Neste artigo, discutimos várias maneiras de criar uma seqüência de caracteres no Groovy e seu suporte a várias linhas, interpolação e regex.

Todos esses trechos estão disponíveis over no Github.

E para obter mais informações sobre os recursos da linguagem Groovy, comece bem com nossa https://www..com/groovy-language [introdução ao Groovy].