# 6. Formatacao de Strings e Cores

### 📋 ÍNDICE

1. Visão Geral da Formatação de Strings
2. Strings em Elixir: Fundamentos
3. Formatação Básica e Interpolação
4. Formatação Avançada com String Module
5. Padding, Alinhamento e Justificação
6. Formatação com Expressões Regulares
7. Cores e Estilos ANSI no Terminal
8. Módulo IO.ANSI - API Completa
9. Exemplos Práticos de Output Colorido
10. Formatação de Relatórios e Tabelas
11. Tratamento de UTF-8 e Caracteres Especiais
12. Performance e Boas Práticas
13. Erros Comuns e Soluções
14. Bibliotecas Externas para Formatação
15. Referência Rápida

***

### 1. VISÃO GERAL DA FORMATAÇÃO DE STRINGS

```yaml
FORMATAÇÃO DE STRINGS EM ELIXIR:

  🎯 OBJETIVOS:
    - Interpolar variáveis em strings
    - Alinhar e justificar texto
    - Aplicar padding e truncamento
    - Adicionar cores e estilos no terminal
    - Processar texto com escape sequences
    - Criar relatórios e tabelas formatadas
  
  🛠️ FERRAMENTAS PRINCIPAIS:
    - Interpolação: "#{var}"
    - Módulo String: 50+ funções de manipulação
    - Módulo IO.ANSI: Cores e estilos
    - Expressões regulares: Regex module
    - Sigils: ~s, ~S, ~w, ~W
  
  📊 CASOS DE USO:
    - Logs coloridos por nível (INFO, WARN, ERROR)
    - CLIs profissionais com feedback visual
    - Relatórios em texto alinhados
    - Geradores de código e templates
    - Validação e sanitização de input
```

***

### 2. STRINGS EM ELIXIR: FUNDAMENTOS

#### 2.1 Strings Binárias vs Charlists

```elixir
# String binária (UTF-8) - PREFERIDA
str = "Olá Mundo"
# Tipo: binary (<<>>)

# Charlist (lista de caracteres) - Compatibilidade com Erlang
charlist = 'Olá Mundo'
# Tipo: [79, 108, 225, 32, 77, 117, 110, 100, 111]

# Conversão entre tipos
to_string('Olá')        # "Olá"
String.to_charlist("Olá")  # 'Olá'

⚠️ Prefira strings binárias (aspas duplas) em Elixir!
```

#### 2.2 Características UTF-8

```elixir
# Tamanho: bytes vs caracteres
str = "café"
byte_size(str)          # 5 (c=1, a=1, f=1, é=2)
String.length(str)      # 4 (caracteres)

# Acesso a caracteres (Unicode graphemes)
String.at("café", 3)    # "é"
String.slice("café", 3, 1)  # "é"

# Iteração segura
String.graphemes("café")  # ["c", "a", "f", "é"]
```

#### 2.3 Sigils para Strings

```elixir
# ~s - String padrão (com interpolação)
~s(Texto com "aspas" sem escapar)
~s(Interpolação funciona: #{var})

# ~S - String sem interpolação (raw)
~S(Interpolação NÃO funciona: \#{var})
~S(Backslash funciona: \\n)

# ~w - Word list (lista de palavras)
~w(uma lista de palavras)  # ["uma", "lista", "de", "palavras"]
~w(uma lista de palavras)a # átomos: [:uma, :lista, :de, :palavras]

# Delimitadores variados
~s/barra funciona/
~s|pipe também|
~s{chaves}
~s[colchetes]
```

***

### 3. FORMATAÇÃO BÁSICA E INTERPOLAÇÃO

#### 3.1 Interpolação de Variáveis

```elixir
# Interpolação simples
nome = "João"
idade = 30
"Olá, #{nome}! Você tem #{idade} anos."
# "Olá, João! Você tem 30 anos."

# Expressões na interpolação
"5 + 3 = #{5 + 3}"                    # "5 + 3 = 8"
"Maior: #{Enum.max([10, 20, 30])}"    # "Maior: 30"
"Lista: #{Enum.join([1,2,3], ",")}"   # "Lista: 1,2,3"

# Múltiplas linhas
"""
Nome: #{nome}
Idade: #{idade}
Status: #{if idade >= 18, do: "Adulto", else: "Menor"}
"""
```

#### 3.2 Concatenação de Strings

```elixir
# Operador <>
"Hello" <> " " <> "World"     # "Hello World"

# Concatenação com conversão automática
"Valor: " <> to_string(42)    # "Valor: 42"

# Join para listas
Enum.join(["a", "b", "c"], "-")   # "a-b-c"
Enum.join([1, 2, 3])              # "123"

# Evite concatenação em loops (use IO.write ou Enum.join)
🚫 ruim: Enum.each(1..1000, fn x -> str = str <> to_string(x) end)
✅ bom: Enum.join(Enum.map(1..1000, &to_string/1), "")
```

#### 3.3 Escape Sequences

```elixir
# Sequências de escape comuns
"\n"   # Nova linha
"\r"   # Carriage return
"\t"   # Tab
"\\"   # Backslash
"\""   # Aspas duplas
"\'"   # Aspas simples

# Exemplo
IO.puts("Linha 1\nLinha 2\tTab")
# Linha 1
# Linha 2   Tab

# Unicode escape
"\u{1F600}"    # 😀 (emoji)
"\u{00E9}"     # é
```

***

### 4. FORMATAÇÃO AVANÇADA COM STRING MODULE

#### 4.1 Transformação de Caixa

```elixir
# Caixa alta/baixa
String.upcase("Elixir")          # "ELIXIR"
String.downcase("ELIXIR")        # "elixir"
String.capitalize("elixir")      # "Elixir"

# Unicode-aware
String.upcase("café")            # "CAFÉ"
String.downcase("CAFÉ")          # "café"
String.capitalize("éLIXIR")      # "Élixir"

# Título (primeira letra de cada palavra)
"hello world" 
|> String.split(" ")
|> Enum.map(&String.capitalize/1)
|> Enum.join(" ")                 # "Hello World"
```

#### 4.2 Trim e Limpeza

```elixir
# Remover espaços em branco
String.trim("  hello  ")          # "hello"
String.trim("  hello  ", " ")     # "hello"

# Trim de caracteres específicos
String.trim("...hello...", ".")   # "hello"
String.trim_leading("  hello")    # "hello"
String.trim_trailing("hello  ")   # "hello"

# Remover múltiplos caracteres
String.trim("__hello__", "_")     # "hello"
```

#### 4.3 Substituição e Reversão

```elixir
# Replace simples
String.replace("hello world", "world", "elixir")  # "hello elixir"
String.replace("a,b,c", ",", " - ")               # "a - b - c"

# Replace global (padrão)
String.replace("banana", "a", "o")                # "bonono"

# Replace apenas primeiro
String.replace("banana", "a", "o", global: false) # "bonana"

# Reverse
String.reverse("elixir")                          # "rixile"

# Reverse Unicode-safe
String.reverse("café")                            # "éfac"
```

#### 4.4 Extração e Divisão

```elixir
# Split simples
String.split("a,b,c", ",")                        # ["a", "b", "c"]
String.split("a b c", " ")                        # ["a", "b", "c"]
String.split("a b c")                             # ["a", "b", "c"]

# Split com limite
String.split("a,b,c,d", ",", parts: 2)            # ["a", "b,c,d"]

# Split em linhas
String.split("linha1\nlinha2\nlinha3", "\n")      # ["linha1", "linha2", "linha3"]

# Extrair primeiro/último
String.first("elixir")                            # "e"
String.last("elixir")                             # "r"

# Slice por posição
String.slice("elixir", 2, 3)                      # "ixi"
String.slice("elixir", 2..4)                      # "ixi"
```

***

### 5. PADDING, ALINHAMENTO E JUSTIFICAÇÃO

#### 5.1 Padding Básico

```elixir
# Padding à esquerda (adiciona caracteres à esquerda)
String.pad_leading("42", 5, "0")          # "00042"
String.pad_leading("abc", 5, "-")         # "--abc"

# Padding à direita
String.pad_trailing("42", 5, "0")         # "42000"
String.pad_trailing("abc", 5, "-")        # "abc--"

# Padding sem caracter especificado (espaço)
String.pad_leading("abc", 5)              # "  abc"
String.pad_trailing("abc", 5)             # "abc  "
```

#### 5.2 Alinhamento Central

```elixir
def center(text, width, padding \\ " ") do
  total_pad = width - String.length(text)
  left_pad = div(total_pad, 2)
  right_pad = total_pad - left_pad
  
  String.duplicate(padding, left_pad) <> 
  text <> 
  String.duplicate(padding, right_pad)
end

# Uso
center("Elixir", 20, "=")   # "=======Elixir========"
center("Hello", 10, " ")    # "  Hello   "
```

#### 5.3 Formatação de Números em Strings

```elixir
def format_number(num, width, decimal_places \\ 2) do
  formatted = :erlang.float_to_list(num, decimals: decimal_places) |> to_string()
  String.pad_leading(formatted, width)
end

format_number(3.14159, 10, 3)        # "      3.142"
format_number(42, 5, 0)              # "   42"

# Moeda
def format_currency(value) do
  "R$ #{:erlang.float_to_list(value, decimals: 2)}"
end

format_currency(1234.5)              # "R$ 1234.50"
```

#### 5.4 Truncamento e Elipsis

```elixir
def truncate(text, max_length, ellipsis \\ "...") do
  if String.length(text) <= max_length do
    text
  else
    String.slice(text, 0, max_length - String.length(ellipsis)) <> ellipsis
  end
end

# Uso
truncate("Uma string muito longa para exibir", 20)  # "Uma string muito..."
truncate("Texto curto", 20)                         # "Texto curto"
```

***

### 6. FORMATAÇÃO COM EXPRESSÕES REGULARES

#### 6.1 Regex para Formatação

```elixir
# Substituir padrões
phone = "(11) 91234-5678"
formatted = Regex.replace(~r/[^0-9]/, phone, "")
# "11912345678"

# Remover espaços extras
text = "texto    com   muitos     espaços"
cleaned = Regex.replace(~r/\s+/, text, " ")
# "texto com muitos espaços"

# Formatar data
date = "2024-01-15"
Regex.replace(~r/(\d{4})-(\d{2})-(\d{2})/, date, "\\3/\\2/\\1")
# "15/01/2024"

# Capitalizar palavras com regex
"hello world from elixir"
|> Regex.replace(~r/\b\w/, fn match -> String.upcase(match) end)
# "Hello World From Elixir"
```

#### 6.2 Regex com Grupos Nomeados

```elixir
# Extrair e reformatar
regex = ~r/(?<nome>\w+), (?<idade>\d+)/
date = "João, 30"

Regex.replace(regex, date, "\\k<nome> tem \\k<idade> anos")
# "João tem 30 anos"

# Formatar com captura
def format_username(username) do
  Regex.replace(~r/^@/, username, "")
end

format_username("@joao123")  # "joao123"
```

***

### 7. CORES E ESTILOS ANSI NO TERMINAL

#### 7.1 Introdução ao IO.ANSI

```elixir
import IO.ANSI

# Cores básicas de foreground
IO.puts(red() <> "Vermelho" <> reset())
IO.puts(green() <> "Verde" <> reset())
IO.puts(blue() <> "Azul" <> reset())
IO.puts(yellow() <> "Amarelo" <> reset())
IO.puts(magenta() <> "Magenta" <> reset())
IO.puts(cyan() <> "Ciano" <> reset())
IO.puts(white() <> "Branco" <> reset())
IO.puts(black() <> "Preto" <> reset())

# Cores de background
IO.puts(red_background() <> "Texto com fundo vermelho" <> reset())
```

#### 7.2 Estilos de Texto

```elixir
import IO.ANSI

# Estilos básicos
IO.puts(bright() <> "Negrito/Brilhante" <> reset())
IO.puts(dim() <> "Esmaecido" <> reset())
IO.puts(italic() <> "Itálico" <> reset())
IO.puts(underline() <> "Sublinhado" <> reset())
IO.puts(blink_slow() <> "Piscando lento" <> reset())
IO.puts(blink_rapid() <> "Piscando rápido" <> reset())
IO.puts(reverse() <> "Cores invertidas" <> reset())
IO.puts(hidden() <> "Oculto" <> reset())
```

#### 7.3 Combinação de Estilos

```elixir
import IO.ANSI

# Combinando múltiplos estilos
estilo = bright() <> red() <> underline()
IO.puts(estilo <> "ERRO CRÍTICO" <> reset())

# Estilo completo
def estilo_erro do
  bright() <> red() <> underline()
end

def estilo_sucesso do
  green()
end

def estilo_warning do
  yellow()
end

# Uso
IO.puts(estilo_erro() <> "[ERROR]" <> reset() <> " Falha na conexão")
```

#### 7.4 Cores 256 e True Color

```elixir
# Cores de 8 bits (256 cores)
IO.puts(IO.ANSI.color(196) <> "Vermelho vivo" <> reset())
IO.puts(IO.ANSI.color(21) <> "Azul intenso" <> reset())

# Background 256 cores
IO.puts(IO.ANSI.color(226, :background) <> "Fundo amarelo" <> reset())

# Cores RGB (True Color) - 24 bits
IO.puts(IO.ANSI.color(255, 0, 0) <> "RGB Vermelho" <> reset())
IO.puts(IO.ANSI.color(0, 255, 0, :background) <> "Fundo RGB Verde" <> reset())
```

***

### 8. MÓDULO IO.ANSI - API COMPLETA

#### 8.1 Funções de Cor

| Função            | Código ANSI | Descrição  |
| ----------------- | ----------- | ---------- |
| `black()`         | 30          | Preto      |
| `red()`           | 31          | Vermelho   |
| `green()`         | 32          | Verde      |
| `yellow()`        | 33          | Amarelo    |
| `blue()`          | 34          | Azul       |
| `magenta()`       | 35          | Magenta    |
| `cyan()`          | 36          | Ciano      |
| `white()`         | 37          | Branco     |
| `default_color()` | 39          | Cor padrão |

#### 8.2 Funções de Background

| Função                 | Código ANSI | Descrição      |
| ---------------------- | ----------- | -------------- |
| `black_background()`   | 40          | Fundo preto    |
| `red_background()`     | 41          | Fundo vermelho |
| `green_background()`   | 42          | Fundo verde    |
| `yellow_background()`  | 43          | Fundo amarelo  |
| `blue_background()`    | 44          | Fundo azul     |
| `magenta_background()` | 45          | Fundo magenta  |
| `cyan_background()`    | 46          | Fundo ciano    |
| `white_background()`   | 47          | Fundo branco   |

#### 8.3 Formatação com Lista

```elixir
# Formatação com lista de códigos
IO.puts(IO.ANSI.format([:red, "Texto vermelho"]))
IO.puts(IO.ANSI.format([:bright, :green, "Texto verde brilhante"]))

# Reset automático
IO.puts(IO.ANSI.format([:red, "Erro", :reset, " ", :green, "Sucesso"]))

# Com escape
IO.puts(IO.ANSI.format([:cyan, "Info", :reset, ": ", "Mensagem"], true))

# Exemplo completo
def color_print(text, color) do
  IO.puts(IO.ANSI.format([color, text]))
end

color_print("Sucesso!", :green)
color_print("Atenção!", :yellow)
```

#### 8.4 Utilitários

```elixir
# Detectar suporte a cores
if IO.ANSI.enabled?() do
  IO.puts("✅ Terminal colorido")
else
  IO.puts("❌ Terminal sem suporte a cores")
end

# Limpar tela
IO.write(IO.ANSI.clear())

# Limpar linha
IO.write(IO.ANSI.clear_line())

# Mover cursor
IO.write(IO.ANSI.cursor_up(5))     # Sobe 5 linhas
IO.write(IO.ANSI.cursor_down(3))   # Desce 3 linhas
IO.write(IO.ANSI.cursor_forward(10)) # Avança 10 colunas
IO.write(IO.ANSI.cursor_back(5))   # Volta 5 colunas

# Salvar/restaurar posição
IO.write(IO.ANSI.save_cursor())
IO.write(IO.ANSI.restore_cursor())
```

***

### 9. EXEMPLOS PRÁTICOS DE OUTPUT COLORIDO

#### 9.1 Logger Colorido por Nível

```elixir
defmodule ColorLogger do
  import IO.ANSI
  
  def info(msg) do
    IO.puts(format_msg(msg, :info))
  end
  
  def warn(msg) do
    IO.puts(format_msg(msg, :warn))
  end
  
  def error(msg) do
    IO.puts(format_msg(msg, :error))
  end
  
  def success(msg) do
    IO.puts(format_msg(msg, :success))
  end
  
  def debug(msg) do
    IO.puts(format_msg(msg, :debug))
  end
  
  defp format_msg(msg, level) do
    timestamp = DateTime.utc_now() |> DateTime.to_string()
    
    level_color = case level do
      :info -> cyan()
      :warn -> yellow()
      :error -> red() <> bright()
      :success -> green()
      :debug -> magenta()
    end
    
    level_name = case level do
      :info -> "[INFO]"
      :warn -> "[WARN]"
      :error -> "[ERROR]"
      :success -> "[✓]"
      :debug -> "[DEBUG]"
    end
    
    IO.ANSI.format([
      :bright, level_color, level_name, reset(),
      " ", timestamp, " ",
      :reset, msg
    ]) |> IO.chardata_to_string()
  end
end

# Uso
ColorLogger.info("Aplicação iniciada")
ColorLogger.warn("Memória em 80%")
ColorLogger.error("Falha na conexão com banco")
ColorLogger.success("Backup concluído")
```

#### 9.2 Barra de Progresso Colorida

```elixir
defmodule ProgressBar do
  import IO.ANSI
  
  def render(current, total, width \\ 50) do
    percent = current / total
    filled = round(percent * width)
    empty = width - filled
    
    bar_color = cond do
      percent < 0.5 -> yellow()
      percent < 0.8 -> cyan()
      true -> green()
    end
    
    bar = String.duplicate("█", filled) <> String.duplicate("░", empty)
    
    IO.write("\r" <> cursor_left(1000))
    IO.write(IO.ANSI.format([
      bar_color, bar, reset(),
      " #{round(percent * 100)}%"
    ]))
    
    if current == total do
      IO.write("\n")
    end
  end
end

# Simulação
Enum.each(1..100, fn i ->
  ProgressBar.render(i, 100)
  Process.sleep(50)
end)
```

#### 9.3 Syntax Highlighter Simples

```elixir
defmodule SimpleHighlighter do
  import IO.ANSI
  
  def highlight(code) do
    code
    |> String.replace(~r/\b(def|defmodule|defmacro)\b/, bright() <> red() <> "\\0" <> reset())
    |> String.replace(~r/"[^"]*"/, green() <> "\\0" <> reset())
    |> String.replace(~r/#.*$/, magenta() <> "\\0" <> reset())
    |> String.replace(~r/\b(\d+)\b/, cyan() <> "\\0" <> reset())
    |> IO.puts()
  end
end

# Uso
code = ~S"""
defmodule Example do
  # Comentário
  def hello(name) do
    "Olá, #{name}!"
  end
end
"""

SimpleHighlighter.highlight(code)
```

***

### 10. FORMATAÇÃO DE RELATÓRIOS E TABELAS

#### 10.1 Tabela Simples com Border

```elixir
defmodule TableFormatter do
  import IO.ANSI
  
  def render_table(headers, rows, title \\ "") do
    col_widths = calculate_column_widths(headers, rows)
    
    # Título
    if title != "" do
      IO.puts(bright() <> title <> reset())
      IO.puts("")
    end
    
    # Header
    print_row(headers, col_widths, :header)
    print_separator(col_widths)
    
    # Rows
    for row <- rows do
      print_row(row, col_widths, :normal)
    end
  end
  
  defp calculate_column_widths(headers, rows) do
    header_widths = Enum.map(headers, &String.length/1)
    rows_widths = rows
    |> Enum.flat_map(&Enum.map(&1, fn cell -> String.length(to_string(cell)) end))
    |> Enum.chunk_every(length(headers))
    
    Enum.zip([header_widths | rows_widths])
    |> Enum.map(fn widths -> Enum.max(widths) end)
  end
  
  defp print_row(row, widths, type) do
    cells = Enum.zip(row, widths)
    |> Enum.map(fn {cell, width} -> 
        cell_str = to_string(cell)
        cell_str <> String.duplicate(" ", width - String.length(cell_str))
      end)
    |> Enum.join(" | ")
    
    row_str = "| " <> cells <> " |"
    
    case type do
      :header -> IO.puts(bright() <> row_str <> reset())
      _ -> IO.puts(row_str)
    end
  end
  
  defp print_separator(widths) do
    sep = widths
    |> Enum.map(&String.duplicate("-", &1 + 2))
    |> Enum.join("+")
    
    IO.puts("+" <> sep <> "+")
  end
end

# Uso
headers = ["Nome", "Idade", "Cidade"]
rows = [
  ["João", 30, "São Paulo"],
  ["Maria", 25, "Rio de Janeiro"],
  ["Pedro", 35, "Belo Horizonte"]
]

TableFormatter.render_table(headers, rows, "Lista de Usuários")
```

#### 10.2 JSON Pretty Print Colorido

```elixir
defmodule JsonPretty do
  import IO.ANSI
  
  def pretty_print(json_string) do
    json_string
    |> Jason.decode!()
    |> do_pretty()
  end
  
  defp do_pretty(data, indent \\ 0) do
    spaces = String.duplicate("  ", indent)
    
    cond do
      is_map(data) ->
        IO.write(spaces <> "{")
        data
        |> Enum.with_index()
        |> Enum.each(fn {{k, v}, i} ->
          IO.write("\n" <> spaces <> "  ")
          IO.write(cyan() <> to_string(k) <> reset() <> ": ")
          do_pretty(v, indent + 1)
          if i < map_size(data) - 1, do: IO.write(",")
        end)
        IO.write("\n" <> spaces <> "}")
      
      is_list(data) ->
        IO.write("[")
        data
        |> Enum.with_index()
        |> Enum.each(fn {v, i} ->
          IO.write("\n" <> spaces <> "  ")
          do_pretty(v, indent + 1)
          if i < length(data) - 1, do: IO.write(",")
        end)
        IO.write("\n" <> spaces <> "]")
      
      is_number(data) ->
        IO.write(green() <> to_string(data) <> reset())
      
      is_boolean(data) ->
        IO.write(yellow() <> to_string(data) <> reset())
      
      is_binary(data) ->
        IO.write(magenta() <> ~s("#{data}") <> reset())
      
      true ->
        IO.write(to_string(data))
    end
  end
end

# Uso
json = ~S"""
{
  "nome": "João",
  "idade": 30,
  "ativo": true,
  "endereco": {
    "cidade": "SP",
    "numero": 42
  }
}
"""

JsonPretty.pretty_print(json)
```

***

### 11. TRATAMENTO DE UTF-8 E CARACTERES ESPECIAIS

#### 11.1 Validação e Sanitização

```elixir
# Verificar se string é UTF-8 válida
def valid_utf8?(string) do
  :unicode.characters_to_binary(string) != :error
end

valid_utf8?("Olá válido")      # true
valid_utf8?("" <> <<255>>)     # false

# Remover caracteres inválidos
def sanitize_utf8(string) do
  :unicode.characters_to_binary(string, :utf8, :ignore)
  |> to_string()
end

# Normalização Unicode
def normalize(string, form \\ :nfd) do
  :unicode.characters_to_nfd_binary(string)
  |> to_string()
end
```

#### 11.2 Emojis e Caracteres Especiais

```elixir
# Emojis em strings
emoji_str = "Olá 😀 Mundo! 🚀"
String.length(emoji_str)  # 13 (cada emoji conta como 1)
byte_size(emoji_str)      # 18+ (emojis ocupam 4 bytes)

# Extrair emojis
def extract_emojis(string) do
  Regex.scan(~r/\p{Emoji}/u, string)
  |> List.flatten()
end

extract_emojis("Olá 😀 e 🚀 e ❤️")  # ["😀", "🚀", "❤️"]

# Contar caracteres especiais
def count_special_chars(string) do
  string
  |> String.graphemes()
  |> Enum.count(&(String.length(&1) > 1))
end
```

#### 11.3 Formatação com Unicode

```elixir
# Linhas horizontais (box drawing)
def draw_line(length, char \\ "─") do
  String.duplicate(char, length)
end

# Caixa Unicode
def draw_box(text) do
    top = "┌" <> String.duplicate("─", String.length(text) + 2) <> "┐"
    middle = "│ " <> text <> " │"
    bottom = "└" <> String.duplicate("─", String.length(text) + 2) <> "┘"
    
    [top, middle, bottom]
    |> Enum.join("\n")
end

draw_box("Elixir")
# ┌────────┐
# │ Elixir │
# └────────┘

# Decodificar entidades HTML
def decode_html_entities(string) do
  string
  |> String.replace("&lt;", "<")
  |> String.replace("&gt;", ">")
  |> String.replace("&amp;", "&")
  |> String.replace("&quot;", "\"")
  |> String.replace("&apos;", "'")
end
```

***

### 12. PERFORMANCE E BOAS PRÁTICAS

#### 12.1 Performance em Strings Grandes

```elixir
# 🚫 Evite concatenação em loops
def bad_concatenation(list) do
  Enum.reduce(list, "", fn item, acc ->
    acc <> to_string(item)  # Cria nova string a cada iteração
  end)
end

# ✅ Use IO.write, IO.puts ou Enum.join
def good_concatenation(list) do
  Enum.join(list, "")
end

# ✅ Para streaming, use IO.write diretamente
def stream_output(list) do
  Enum.each(list, &IO.write/1)
end

# ✅ Acumular em lista e depois join
def accumulate_then_join(list) do
  list
  |> Enum.map(&to_string/1)
  |> Enum.join("")
end
```

#### 12.2 Cache de Strings Formatadas

```elixir
# Cache de strings formatadas em módulo
defmodule FormattedStrings do
  @colors %{
    info: IO.ANSI.cyan(),
    error: IO.ANSI.red() <> IO.ANSI.bright(),
    warn: IO.ANSI.yellow(),
    success: IO.ANSI.green()
  }
  
  @reset IO.ANSI.reset()
  
  def format(level, message) do
    @colors[level] <> message <> @reset
  end
end
```

#### 12.3 Middleware de Formatação

```elixir
defmodule FormatMiddleware do
  import IO.ANSI
  
  def with_color(f, color) do
    IO.write(color())
    result = f.()
    IO.write(reset())
    result
  end
  
  def with_bright(f) do
    IO.write(bright())
    result = f.()
    IO.write(reset())
    result
  end
  
  # Uso
  FormatMiddleware.with_color(fn ->
    IO.puts("Texto colorido")
  end, :red)
end
```

***

### 13. ERROS COMUNS E SOLUÇÕES

#### 13.1 Problemas com UTF-8

```elixir
# ❌ Erro: byte_size vs String.length
str = "café"
byte_size(str) == String.length(str)  # false (5 vs 4)

# ✅ Sempre use String.length para contar caracteres
String.length(str)  # 4

# ❌ Erro: Cortar por bytes
binary_part(str, 0, 4)  # Pode cortar no meio de caractere

# ✅ Use String.slice
String.slice(str, 0, 4)  # "café"
```

#### 13.2 Problemas com ANSI Codes

```elixir
# ❌ Esquecer reset()
IO.puts(IO.ANSI.red() <> "Erro")
# Próximos outputs ficarão vermelhos

# ✅ Sempre use reset()
IO.puts(IO.ANSI.red() <> "Erro" <> IO.ANSI.reset())

# ❌ Assumir que terminal suporta cores
if !IO.ANSI.enabled?() do
  IO.puts("Terminal sem suporte a cores, usando formato básico")
end

# ✅ Verificar suporte
def colorize(text, color) do
  if IO.ANSI.enabled?() do
    color <> text <> IO.ANSI.reset()
  else
    text
  end
end
```

#### 13.3 Problemas de Performance

```elixir
# ❌ Regex não compilado em loop
def bad_regex_loop(list) do
  Enum.map(list, fn item ->
    Regex.replace(~r/\s+/, item, " ")  # Compila regex a cada iteração
  end)
end

# ✅ Regex compilado uma vez
def good_regex_loop(list) do
  regex = ~r/\s+/
  Enum.map(list, fn item ->
    Regex.replace(regex, item, " ")
  end)
end
```

***

### 14. BIBLIOTECAS EXTERNAS PARA FORMATAÇÃO

#### 14.1 Principais Bibliotecas

```elixir
# 📦 Colorful - API mais simples para cores
# mix.exs: {:colorful, "~> 0.1"}
import Colorful

IO.puts(red("Erro fatal"))
IO.puts(blue().bright().italic("Destaque"))
IO.puts(green_background().white("Sucesso"))

# 📦 Table - Formatação de tabelas
# {:table, "~> 0.1"}
data = [[1, "João", 30], [2, "Maria", 25]]
IO.puts(Table.render(data, header: ["ID", "Nome", "Idade"]))

# 📦 Inflex - Transformações de strings
# {:inflex, "~> 2.0"}
Inflex.pluralize("user")           # "users"
Inflex.camelize("user_name")       # "UserName"
Inflex.parameterize("Olá Mundo!")  # "ola-mundo"

# 📦 Cldr - Formatação internacional
# {:ex_cldr, "~> 2.0"}
Cldr.Number.to_string(1234.56, locale: "pt-BR")  # "1.234,56"
Cldr.Date.to_string(~D[2024-01-15], locale: "pt") # "15 de janeiro de 2024"
```

#### 14.2 Exemplo Colorful + Table

```elixir
defmodule Reports do
  import Colorful
  alias Table
  
  def generate_metrics(metrics) do
    IO.puts(bold().underline(blue("📊 Métricas do Sistema")))
    IO.puts("")
    
    Table.render(metrics, header: [:green("Métrica"), :yellow("Valor")])
    
    IO.puts("")
    IO.puts(green("✅ Relatório gerado com sucesso"))
  end
end

metrics = [
  ["CPU", "45%"],
  ["Memória", "2.1 GB"],
  ["Disco", "120 GB"]
]

Reports.generate_metrics(metrics)
```

***

### 15. REFERÊNCIA RÁPIDA

#### 15.1 Tabela de Funções Essenciais

| Categoria      | Função                  | Descrição            |
| -------------- | ----------------------- | -------------------- |
| **Strings**    | `"#{var}"`              | Interpolação         |
|                | `str1 <> str2`          | Concatenação         |
|                | `String.length/1`       | Tamanho (caracteres) |
|                | `byte_size/1`           | Tamanho (bytes)      |
|                | `String.upcase/1`       | Para maiúsculo       |
|                | `String.downcase/1`     | Para minúsculo       |
|                | `String.trim/1`         | Remove espaços       |
|                | `String.pad_leading/3`  | Padding esquerda     |
|                | `String.pad_trailing/3` | Padding direita      |
|                | `String.replace/3`      | Substituição         |
|                | `String.split/2`        | Divide string        |
|                | `String.slice/3`        | Fatiamento           |
| **Cores ANSI** | `IO.ANSI.red()`         | Cor vermelha         |
|                | `IO.ANSI.green()`       | Cor verde            |
|                | `IO.ANSI.blue()`        | Cor azul             |
|                | `IO.ANSI.bright()`      | Negrito              |
|                | `IO.ANSI.underline()`   | Sublinhado           |
|                | `IO.ANSI.reset()`       | Reset estilos        |
|                | `IO.ANSI.enabled?/0`    | Verifica suporte     |

#### 15.2 Convenções

```elixir
# ✅ Boas práticas
1. Use String.length/1 em vez de byte_size/1 para caracteres
2. Sempre use IO.ANSI.reset() após formatação
3. Prefira Enum.join para concatenação de listas grandes
4. Compile regex fora de loops
5. Verifique IO.ANSI.enabled?() antes de usar cores

# ❌ Evite
1. Concatenação em loops (str = str <> new)
2. KEYS * em produção (use SCAN)
3. Regex sem compilação prévia
4. Assumir terminal colorido
5. Ignorar diferença entre bytes e caracteres
```

#### 15.3 Links Úteis

* [Documentação String](https://hexdocs.pm/elixir/String.html)
* [Documentação IO.ANSI](https://hexdocs.pm/elixir/IO.ANSI.html)
* [Unicode no Elixir](https://elixir-lang.org/getting-started/binaries-strings-and-char-lists.html)
* [ANSI Escape Codes](https://en.wikipedia.org/wiki/ANSI_escape_code)

***

### METADADOS FINAIS

* **Mantido por:** Equipe de Documentação Técnica
* **Última atualização:** 2026-05-06
* **Versão da tecnologia:** Elixir 1.15+
* **Tags relevantes:** `elixir`, `strings`, `formatting`, `ansi-colors`, `unicode`, `terminal-output`


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://0xmorte.gitbook.io/bibliadopentestbr/conceitos/programacao-e-linguagens/elixir/6.-formatacao-de-strings-e-cores.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
