Strings em Swift: por que substring não funciona como você está acostumado?

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: A "armadilha" que espera cada desenvolvedor Swift

\n\n

Imagine a situação: você está escrevendo código em Swift com confiança, tudo está indo bem, e de repente você precisa pegar os três primeiros caracteres de uma string. Você, sem pensar, escreve algo como myString[0..<3] — e recebe... um erro de compilação. Familiar?

\n\n

Bem-vindo ao mundo do String substring em Swift. Este é um daqueles tópicos que causam verdadeira dor em iniciantes e até mesmo em desenvolvedores experientes vindos de outras linguagens. A pergunta "How does String substring work in Swift" no Stack Overflow acumulou milhares de visualizações — e não é por acaso.

\n\n

Neste artigo, vamos analisar por que o Swift é tão "estranho" ao trabalhar com substrings, como usar corretamente o substring em Swift e quais novos recursos surgiram nas versões mais recentes. Vamos lá!

\n\n

Por que o Swift não permite simplesmente cortar um pedaço da string?

\n\n

Na maioria das linguagens (Python, JavaScript, C#), uma string é apenas um array de caracteres. Quer uma substring? Escreva str[0:3] e obtenha o resultado. No Swift, é diferente.

\n\n

A razão está no trabalho com Unicode. Strings em Swift não são apenas bytes ou caracteres ASCII. Elas consistem em clusters de grafemas (grapheme clusters). Um único caractere que o usuário vê (por exemplo, "é" ou "👍🏽") pode ocupar vários Character ou até vários Unicode.Scalar. Imagine que você corta uma string no meio de um desses clusters — você obterá dados corrompidos.

\n\n

Por isso, o Swift usa índices (String.Index), em vez de números inteiros. Isso garante que você nunca divida um caractere ao meio.

\n\n

Fundamentos: String.Index e extração simples de substring

\n\n

Vamos começar com um exemplo básico. Suponha que temos uma string:

\n\n
let fullString = "Olá, Swift!"\n// Queremos pegar a palavra "Swift"\nlet startIndex = fullString.index(fullString.startIndex, offsetBy: 5)\nlet endIndex = fullString.index(fullString.startIndex, offsetBy: 10)\nlet substring = fullString[startIndex..<endIndex]\nprint(substring) // Exibirá: "Swift"
\n\n

Observe: substring tem o tipo Substring, não String. Esta é uma diferença importante. Substring é uma "janela" para a string original. Ela não copia os dados, apenas faz referência a uma parte da memória da string original. Isso é super eficiente, mas pode levar a vazamentos de memória se a string original for grande e a substring for pequena.

\n\n

Para transformar Substring em uma String completa, basta usar o inicializador:

\n\n
let newString = String(substring)\nprint(newString) // "Swift"
\n\n

Açúcar sintático: RangeExpression

\n\n

Escrever index(offsetBy:) toda vez é cansativo. Felizmente, o Swift permite usar formas mais curtas com RangeExpression.

\n\n

Operador ... (ClosedRange)

\n
let str = "Olá, Mundo!"\nif let range = str.range(of: "Mundo") {\n    let mundoSubstring = str[range]\n    print(mundoSubstring) // "Mundo"\n}
\n\n

Intervalos parciais (Partial Range)

\n

Quer pegar tudo até um determinado índice ou depois dele? Fácil:

\n
let texto = "Swift Programação"\nlet prefixo = texto[..<texto.index(texto.startIndex, offsetBy: 5)]\nprint(prefixo) // "Swift"\n\nlet sufixo = texto[texto.index(texto.startIndex, offsetBy: 6)...]\nprint(sufixo) // "Programação"
\n\n

Observe: prefixo e sufixo também são Substring.

\n\n

Métodos integrados: prefix, suffix, dropFirst, dropLast

\n\n

O Swift fornece métodos convenientes que eliminam a necessidade de calcular índices manualmente. Eles retornam Substring.

\n\n