segunda-feira, 30 de janeiro de 2012

Instalando NetBeans no Windows


A plataforma de desenvolvimento NetBeans é um projeto Open Source fundado pela Sun Microsystem  em junho de 2000. Ainda hoje com a Oracle continua sendo seu principal patrocinador. O NetBeans IDE é um ambiente de desenvolvimento que permite escrever, compilar, depurar e implantar programas.

Este programa é escrito em Java porém é capaz de suportar qualquer linguagem de programação. Neste post vamos ver a instalação completa da ferramenta. Existem, ainda, grande número de módulos (ou plugins) para aprimorar o NetBeans. Esta IDE é gratuita e sem restrições de uso.

Para fazer o download vá para http://netbeans.org.


domingo, 29 de janeiro de 2012

Swing

Java SE possui um framework para criar GUI na linguagem Java. Java Foundation Class (JFC) é formada por:



  • Componentes GUI do Swing
Inclui componentes visuais como botões, tabelas, painéis, etc permitindo funções como ordenação, impressão, drag'n'drop.

  • suporte a Pluggable Look-and-Feel
A aparência dos aplicativos Swing é configurável, permitindo ao programador escolher mostrar a aparência do Wndows, GTK+, Java, inclusive existem outras fontes disponíveis.

  • API de acessibilidade
Habilita tecnologias assistivas tais como leitores de tela e displays Braille.

  • Java 2D API
Permite incorporar gráficos 2D, texto e imagens nos programas e applets.

  • Internationalização
Permite que os desenvolvidores criem programas que interagem com usuários em sua língua nativa e convenções locais (moeda, formato de data e hora etc).

Para todos os efeitos podemos considerar a AWT (Abstract Window Toolkit) como parte da JFC, apesar da AWT existir antes disto. A API do Swing é muito grande, poderosa e flexível - e é nesta API que iremos nos concentrar nos próximos posts. São 18 pacotes públicos:
  • javax.accessibility
  • javax.swing.plaf
  • javax.swing.text
  • javax.swing
  • javax.swing.plaf.basic
  • javax.swing.text.html
  • javax.swing.border
  • javax.swing.plaf.metal
  • javax.swing.text.html.parser
  • javax.swing.colorchooser
  • javax.swing.plaf.multi
  • javax.swing.text.rtf
  • javax.swing.event
  • javax.swing.plaf.synth
  • javax.swing.tree
  • javax.swing.filechooser
  • javax.swing.table
  • javax.swing.undo
Normalmente utilizamos somente uma pequena fração destas APIs, principalmente:
  • javax.swing
  • javax.swing.event (not always required)

Para utilizar estes recursos de GUI iremos utilizar uma ferramenta gratuita da Oracle denominada NetBeans que pode ser baixada em http://netbeans.org/downloads/.

terça-feira, 17 de janeiro de 2012

Expressões Regulares VII

Para finalizar este assunto de quantificadores temos que explicar os tais tipos: GreedyReluctantPossessive. Vamos ver:
  • Greedy: estes quantificadores forçam a procura a ler toda a string antes de tentar localizar o primeiro resultado. Se a primeira tentativa (toda string) falha, a pesquisa fornece um caracter e tenta novamente, repetindo o processo até achar ou que não hajam mais caracteres. Dependendo do quantificador, a última tentativa será com 1 ou zero caractere.
  • Reluctant: este tipo de quantificador faz uma busca ao contrário do Greedy. Começa pela menor string possível (0 ou 1 caracter dependendo o outro quantificador) até tentar com a string completa.
  • Possessive: processam toda a string e tentam achar a sequência pesquisada somente uma vez (e não mais).

Vamos considerar os exemplos rodados acima.

Com .*casa o matcher irá procurar qualquer caracter que apareçam zero ou mais vezes seguida pela palavra casa. Como * é um quantificador do tipo Greedy. O programa irá tentar consumir toda a string  primeiro - irá tentar achar algo + casa, mas como tudo foi consumido, não acha nada. O programa irá colocar para pesquisa a letra mais a direita da string original - a - e realiza a pesquisa com ela. Também não acha. Esta pesquisa vai expandindo até o programa ter expandido para os 4 caracteres da direita que fornecem casa, que equivale a zero caracteres + casa, portanto a pesquisa para.

O segundo exemplo que é reluctant e portanto funciona o contrário. Assim a pesquisa começa com a string completa e tentar achar algo + casa, e acha o primeiro resultado indicado. O matcher remove o caracter mais a esquerda, resultando na string casaaaaaaaaaacasa e faz novo teste, não achando resultado. A string é sistematicamente reduzida até acasa, quando o teste consegue localizar novamente a string pesquisada. Para esclarecer veja abaixo:
Um pouco menos confuso?

Retornamos ao terceiro quantificador - possessive. Como a string é consumida na primeira tentativa, não acha resultado. A Oracle recomenda que somente utilizemos este tipo de pesquisa, quando queremos achar toda a string de uma só vez.



E para terminar este post vamos tratar das expressões de fronteira. As expressões que utilizamos até agora localizavam um conjunto de caracteres em qualquer posição da string, sem se importar com onde este conjunto estava localizado. A utilização destas expressões de fronteira permitem que tentemos localizar um conjunto de caracteres, mas somente se estiver no início ou final da linha e assim por diante.

As principais expressões são:


Expressão
Regex
Significado
^representa o início da linha
$representa o final da linha
\brepresenta uma palavra
você se lembra [a-zA-Z0-9]
\Brepresenta uma fronteira que não é palavra
é o contrário de \b
\Arepresenta o início da entrada
\Grepresenta o final da última sequência encontrada
\Zrepresenta o final da entrada
\zrepresenta o final da entrada

Vamos tentar uns exemplos:

O primeiro exemplo não achou, pois a string não começa com pedra, enquanto o segundo exemplo funciona, pois a frase começa com No. O terceiro exemplo também acha, pois a frase termina com pedra. A última também acha 4 ocorrências de pedra que estão no texto.

Para finalizar este post vamos tentar com \b e \B:


segunda-feira, 16 de janeiro de 2012

Expressões Regulares VI

Vamos ver agora nesta continuação dos quantificadores as expressões que utilizam {}. Vamos testar uma sequência de letras a:

Veja que pesquisamos a{3} isto é uma sequência com 3 letras a. Notem que:

  • a expressão retornou resultado quando achou uma ou mais sequencias de 3 letras;
  • cada conjunto é indicado na saída do grupo;
  • quando a string pesquisada tinha 4 letras ela somente retorna o primeiro conjunto de 3 letras, desconsiderando a letra a final.

Uma variação é com a{3,} que quer dizer ache uma sequência com pelo menos 3 letras a seguidas. Testem a string com 6 letras a seguidas... vocês verão que o resultado é somente um grupo.

Vamos testar agora a última variação a{3,5}. Como vimos na definição, esta expressão irá retornar sequências de 3 até 5 letras a.
Vejam pelos exemplos que uma sequência aaa, aaaa e aaaaa retornam um conjunto. Se forem seis letras, encontra somente um conjunto composto pelas 5 primeiras letras. E oito letras seguidas?
Isto mesmo: duas sequências, a primeira com 5 letras e a segunda com 3.

Parece meio chato esta história de procurar letras, mas podemos procurar conjuntos de letras (sejam palavras ou não). Vejam o exemplo abaixo:

Que tal uma cantiga de roda para terminar este post?

A expressão é bem mais complicada, mas dá para ver que podemos juntar tudo que aprendemos até agora.

sexta-feira, 13 de janeiro de 2012

Expressões Regulares V

Vamos ver agora algo bastante difícil de lembrar - são os qualificadores nas expressões regex.

GreedyReluctantPossessiveSignificado
x?x??x?+acha x, se aparece uma vez ou nenhuma
x*x*?x*+acha x, se aparece zero ou mais vezes
x+x+?x++acha x, se uma ou mais vezes
x{n}x{n}?x{n}+acha x, se exatamente n vezes
x{n,}x{n,}?x{n,}+acha x, se pelo menos n vezes
x{n,m}x{n,m}?x{n,m}+acha x, se pelo menos n vezes, mas não mais que m vezes

Fácil? Também acho complicado.
Primeiro fato o tipo do qualificador é dado pelo sufixo. Vamos voltar na tabela acima. Todos os qualificadores greedy não tem um sufixo especial, os qualificadores reluctant tem uma interrogação no final e os possessive tem um sinal de mais no final.

Vamos testar uma pesquisa do caracter a, com algumas variações para ver se conseguimos entender:

No caso da string pesquisada estar vazia, vemos que a? e a* retornam resultados. Por quê? Se lemos a definição, estas duas opções retornam quando existem zero ocorrências do caracter procurado - daí o resultado de ter encontrado na posição zero. Como a string é nula, a+ não encontra, afinal não tem nada para ser encontrado e é necessária pelo menos uma ocorrência.

Quando colocamos um único a na string pesquisada, os resultados são diferentes.  Vemos que a? e a* retornam os mesmos resultados. Apesar disto os motivos são diferentes, a? retorna dois resultados, porque só existem 2 resultados possíveis: o caracter só aparece uma vez (afinal a string só tem uma letra a) e o resultado para nenhum vez. Desta vez a+ já retorna um resultado, pois a letra aparece uma (única) vez.

Quanto a string pesquisada é aaa, os resultados são ainda mais inusitados. a? divide a string em 4 blocos, são as três ocorrências da letra procurada e o final. a* acha 2 blocos, um composto pelo conjunto das letras repetidas e um vazio. a+ acha somente o bloco com as letras repetidas.

Vejam o resultado a seguir. Ficou mais fácil de entender?


Continua na 6ª parte deste post.

quinta-feira, 12 de janeiro de 2012

Expressões regulares IV

Existem diversos conjuntos de padrões de caracteres que representam nas expressões regulares um subconjunto de caracteres. Nós já utilizamos um deles - o ponto que representa qualquer caracter. Os mais comuns são:


Expressão
Regex
Significado
.representa qualquer caracteres
\drepresenta um dígito [0-9]
\Drepresenta um caracteres que não é um dígito.
Equivale ao intervalo [^0-9]
\srepresenta um espaço.
\Srepresenta qualquer outro caracter que não é espaço.
Equivale a [^\s]
\wrepresenta o conjunto de caracteres alfanuméricos.
Equivale a [a-zA-Z0-9]
\Wrepresenta qualquer outro caracteres não alfanumérico.
Equivale a [^\w]

Estas expressões são chamadas escaped constructs. Se formos montar uma declaração Java é necessário acrescentar mais uma barra como no exemplo abaixo:

private final String REGEX = "\\s"; // um espaço

Vamos ver um exemplo:



quarta-feira, 11 de janeiro de 2012

Expressões Regulares III

Continuando a saga das expressões regulares, vamos experimentar a negação. Neste caso são considerados todos os caracteres exceto aqueles listados. Vamos ver uns exemplos:


Veja que achou todos os caracteres exceto [abc]. Podemos escrever [abc] como [a-c]. Este formato é o de intervalos ou faixas. Vamos ver alguns testes.


No 1º exemplo acima vemos que só listou 3 elementos, pois Arq4 tem a primeira letra em maiúscula e como a busca é sensível ao caso não funciona. No 3º exemplo, consertamos isto. Veja que mesmo uma coisa aparentemente absurda como a pesquisa [a-f][aeiou][rte] em um trecho do romance Helena de Machado de Assis retorna alguns resultados. Veja que foram localizadas as combinações [eir], [bar], [dor], [cur], [dar] e [for]. Se olharmos para a expressão regex vemos que a primeira letra de cada combinação está entre a e f, a segunda é uma vogal e a terceira é r, t ou e.

Podemos utilizar de negação juntamente com a seleção de faixas:

Vamos dizer que temos uma base de dados numérica e queremos achar números entre 3200 e 3299, exceto os terminados com 3, 4, 5 ou 6.

Usamos 32.. para localizar conjuntos de 4 elementos começados com 32. Conseguimos localizar uma parte da nossa seleção. Mas não conseguimos retirar os elementos indesejados. Para isto temos que tratar os 2 caracteres finais de expressão.

Utilizamos então a expressão 32.[^3-6], conseguimos retirar as sequências terminadas em 3, 4, 5 ou 6, mas ainda estamos obtendo alguns resultados indesejados como por exemplo [326 ].
Para ter certeza que só estamos pesquisando números não podemos utilizar [.], temos que filtrar pelos números, ou seja, utilizar a expressão [0-9]. Assim a expressão final fica 32[0-9][0-9&&[^3-6]]. Parece confuso não é? Veja abaixo o resultado. É o queríamos. Vamos entender então a expressão

3     --> o primeiro caracter é sempre 3
2     --> o segundo caracter é sempre 2
[0-9] --> o terceiro caracter é 0, 1, 2, 3, 4, ... até 9
[0-9&&[^3-6]] --> o quarto caracteres aceita somente números, mas são desconsi-
                  derados os números de 3 a 6. Lembrando [^3-6] quer dizer
                  caracteres que não estão na faixa de 3 a 6.


Continua em quarta parte >>>

terça-feira, 10 de janeiro de 2012

Expressões regulares II

Agora vamos tentar uma expressões mais complicadas.


Expressão RegexSignificado
[abc]busca os caracteres a, b ou c
[^abc]É uma negação da busca (o inverso da linha de cima), quer dizer que busca qualquer caracter menos a, b ou c
[a-zA-Z]Define um intervalo de busca, que contem de a a z (minúsculas ou maiúsculas)
[a-d[m-p]]Realiza uma operação de união, considera os caracteres de a a d ou m a p
[a-dm-p]
[a-z&&[def]]Esta é uma operação de interseção. O resultado serão caracteres que estejam simultaneamente na faixa de a a z e sejam iguais a d, e ou f.
Este é um exemplo estúpido pois é a mesma coisa de [def]
[a-z&&[^bc]]Esta subtração já é melhor. Considera caracteres de a a z, exceto os iguais a b e c.
Esta operação equivale a [ad-z]
[a-z&&[^m-p]]Considera caracteres de a a z, exceto os aqueles entre m e p.
Esta operação equivale a [a-lq-z]
Note que o conteúdo entre colchetes representa um único caracter.

Busca

Se lembrarmos que o Java e Linux são sensíveis ao caso, imagine procurar nos diretórios planilhas de relatório. Sabemos que elas chamam relatório e terminam com .xls. Como fazer isto em regex?
A expressão [rR]elat[oó]rio\.xls é uma primeira aproximação considerando o que já vimos até agora.



Mais para frente veremos um aprimoramento desta pesquisa.


Operação de União



Continua na parte III >>>.

segunda-feira, 9 de janeiro de 2012

Expressões Regulares I

Uma das coisas mais difíceis para o pessoal que desenvolve em Windows é apresentar a utilizar as expressões regulares ou regex. O pessoal do linux que já trabalham com administração mais avançada nos terminais vão encontrar estas expressões até mesmo nas linhas de comando. Parece um bicho de 8 cabeças (e não vou mentir, início é mesmo e depois a gente ainda se enrola nas expressões mais complicadas), mas o uso vai fixando esta idéia na cabeça da gente.

Para utilizar estas expressões você vai achar um pacote no Java denominado java.util.regex. Sugiro dar uma olhada na documentação no site da Oracle para mais detalhes. Este pacote oferece:
  • uma Interface:
    •  MatchResult
  • duas Classes:
    • Matcher
    • Pattern
  • uma Exceção:
    • PatternSyntaxException
A classe Pattern é uma representação compilada pelo Java da expressão. Esta classe não possui construtores, portanto para criar um padrão compilado devemos chamar inicialmente Pattern.compile que retorna um objeto do tipo Pattern. Este método aceita a expressão regex como argumento principal.

A classe Matcher é o interpretador do padrão e busca os resultados da operação sobre a string. Esta classe também não tem construtor público, e um objeto é criado chamando pattern.matcher.

PatternSyntaxException é uma exceção (não verificada) que indica que há um erro na sintaxe da regex.

Vamos ver um exemplo para testar os padrões. A classe abaixo é uma modificação da classe RegexTestHarness da Oracle que permite que entremos com uma expressão regular e uma string e a classe executa a expressão regular sobre a string apresentando o resultado da pesquisa. Acho ela muito prática para aprender qual o comportamento do matcher para um determinado padrão, pois nos permite simular diversos padrões.

import java.io.Console;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class TestaExpressoesRegex {

  public static void main(String[] args){
    // usamos esta classe para ler a entrada de dados a partir da console
    // (prompt de comando do windows ou terminal no linux)
    Console console = System.console();
    if (console == null) {
      System.out.println("Não foi localizada a console (prompt)!");
      System.exit(1); // sai com erro
    }
    // loop sem fim
    while (true) {
      // cria a classe que manipula o padrão - string com a pesquisa regex
      Pattern pattern = Pattern.compile(console.readLine("Entre com a expressao regex      : "));
      //o texto digitado na console é enviado para o método Pattern.matcher
      // que processa a string frente ao padrão regex
      // o resultado é Matcher
      Matcher matcher = pattern.matcher(console.readLine("Entre com o texto a ser pesquisado : "));
      // loop para apresentar o resultado --> podem existir diversos resultados
      // em função da repetição do padrão
      boolean achou = false;
      while (matcher.find()) { // enquanto achou padrao
        console.format("Encontrado o texto [%s] na posição de %d a %d.%n",
          matcher.group(), // texto encontrado
          matcher.start(), // posição inicial
          matcher.end());  // posição final
        achou = true;
      }
      if(!achou ){
        console.format("Não foram encontradas mais entradas.%n");
      }
    }
  }
}

Para entendermos melhor o funcionamento desta classe, vamos executar alguns testes com ela e analisar os resultados.



A procura funciona mesmo tendo acrescentado o ponto no final da expressão regex, isto acontece por que este ponto é considerado um metacaracter. Veja que os resultados (grupos) encontrados foram roe, rou e rom.

Os metacaracteres são caracteres especiais que são interpretados pelo matcher de forma diferente. Neste exemplo o "." quer dizer qualquer caracter. É por isto que o segundo exemplo funciona também.

Existem diversos metacaracteres suportados por java.util.regex, eles são:
<([{\^-=$!|]})?*+.>

E se queremos procurar por uma string que tenha ponto (ou qualquer outro metacaracter)?

Existem duas maneiras de informar ao interpretador regex que o metacaracter deve ser tratado como um caracter ordinário:
  1. colocar uma barra invertida antes do metacaracter (por exemplo \.)
  2. colocar os metacaracteres entre \Q e \E (por exemplo
\Q<([{\^-=$!|]})?*+.>\E 
permite procurar a lista de todos os metacaracteres).
Continua na parte I >>>

quinta-feira, 5 de janeiro de 2012

Renomeando - Parte II

Nós vimos na postagem anterior que java.io.File permite renomear arquivos do sistema operacional. A nova versão java.nio também possui este recurso que vamos explorar aqui.

Primeiro a nossa classe de exemplo (lembrem que só vai compilar se seu Java SE for 7) :

import java.nio.file.*;
import java.io.IOException;


/**
* @param arg[0] padrao a ser procurado
* @param arg[1] novo valor
* @param arg[2] arquivo ou diretorio
* @param arg[3] arquivo ou diretorio
* ....
*/
class Renomear {


  String padrao;
  String novoPadrao;


  public Renomear(String seq, String novaSeq) {
    padrao = seq;
    novoPadrao = novaSeq;
  }




  public void executar(String arquivo) {
    Path f = FileSystems.getDefault().getPath(arquivo);
    // getFileName() retorna Path por isto temos que encadear 
    // com .toString() para procurar pelo padrao
    String nomeArquivo = f.getFileName().toString();
    if (nomeArquivo.contains(padrao)) {
      // move() funciona para mover um arquivo ou para renomea-lo
      try {
        Files.move(f, f.resolveSibling( nomeArquivo.replace(padrao, novoPadrao) ));
      } catch (IOException e) {
        System.out.println(e.toString());
      }
    } 
  }


  public static void main(String[] args) {
    
    if (args.length < 3) {
      System.out.println("Uso: java Renomear \"padrao original\" \"novo padrao\" {nomeArquivo|nomeDiretorio} [{nomeArquivo|nomeDiretorio}]");
      System.exit(0); // sair
    }


    Renomear r = new Renomear(args[0], args[1]);
    for(int i = 2; i < args.length; i++)
      r.executar(args[i]); // renomeia cada arquivo da lista


  }
}

Compilamos, rodamos e (acreditem) funciona!
O padrão procurado foi "~" que será trocado por "lll". Um dos arquivos selecionado na lista está marcado com a seta. Na imagem abaixo está o resultado.

Vamos ver o que foi utilizado:
  • FileSystems.getDefault() retorna o objeto FileSystem default que utilizaremos para obter o path para o arquivo. Este método retorna FileSystem e por isto podemos utilizar o método abaixo.
  • FileSystems.getDefault().getPath(String s) converte uma String com um caminho e retorna um objeto do tipo Path que pode ser utilizado para localizar e/ou acessar um arquivo.
  • Path.getFileName() retorna um Path com o nome do arquivo (ou diretório) representado pelo objeto Path.
  • Path.toString() retorna uma String com o caminho do arquivo/diretório. Em função disto podemos usar uam chamada com Path.getFileName().toString() para obter o nome do arquivo como String.
  • Files.move() tem o seguinte formato move(Path origem, Path destino, CopyOption opcoes). Este terceiro parâmetro é opcional e nós não utilizamos. move() permite mover ou renomear o arquivo da mesma maneira que o comando mv do linux.
  • Path.resolveSibling(String s) converte uma string em um caminho, utilizando o caminho original. Por exemplo:
    • se temos um Path p com "/var/log/system"
    • Path p1 = p.resolveSibling("system.1");
    • p1 vai ser "/var/log/system.1"
Bacana!

quarta-feira, 4 de janeiro de 2012

Criando diretórios - II

A partir da versão 7 do Java existe um novo pacote denominado java.nio que implementa e melhora várias coisas que já existiam no java.io. Vamos ver o nosso exemplo para criar diretórios:


import java.nio.file.*;
import java.io.IOException;


public class CriaDirectories { 
  
  public static void main(String[] args) {
    // usa o args[0] para indicar o que queremos criar
    Path dir = FileSystems.getDefault().getPath(args[0]); 
try {
 Path p = Files.createDirectories(dir);
 System.out.println(p.toString());
} catch (IOException e) { // createDirectories() gera IOException
 System.out.println(e.toString());  
}
  }
}

Vejam que ele ficou muito diferente do outro. Utilizamos duas novas classes Path e Files. Esta segunda é estática.


Existe também o método createDirectory() que realiza função equivalente a java.io.File.mkdir(). As funções tem a forma genérica de:

  • createDirectory(Path d, FileAttributes<?> attr)
  • createDirectories(Path d, FileAttributes<?> attr)

Ambas retornam Path (como no exemplo acima) indicando o diretório.
O parâmetro d é obviamente o diretório que queremos criar (notem que é um objeto do tipo Path), dai a linha para criação do objeto dir a partir de args[0] no exemplo.


attr é uma lista opcional composta pelo par (String nomeDoAtributo, T valorDoAtributo) que desejamos setar para o diretório.

terça-feira, 3 de janeiro de 2012

Criando diretórios

Na classe java.io.File existem dois métodos para gerar


  • mkdir(): cria um diretório de acordo com o pathname que foi passado
  • mkdir(): cria um diretório de acordo com o pathname que foi passado, incluindo todos os subdiretórios necessários

Ambos os métodos retornam true se conseguiram criar o diretório.

Vamos ver um exemplo. Utilizando mkdir() conseguimos criar um diretório a partir do que estamos ("."), mas não conseguimos criar um diretório e seu subdiretório em um único comando. Já com mkdirs() esta segunda opção também funciona.


segunda-feira, 2 de janeiro de 2012

Apagando arquivos com Java

Continuando a utilizar a classe File temos um outro exemplo bacana e simples... para apagar arquivos.


import java.io.File;
/**
* remove os arquivos listados
* @param arg[0] arquivo ou diretorio a ser removido
* @param arg[1] igual ... 
*/
public class ApagaArquivos { 
  public static void main(String[] args) {
    if (args.length < 1) {
      System.out.println("Uso: java ApagaArquivos {nomeArquivo|nomeDiretorio} ...");
      System.exit(0); // sair
    }


    for(int i=0; i<args.length; i++) {
      File f = new File(args[i]);
      f.delete();
    }   
  }
}


E o resultado é: