Olá pessoal,
Não sou muito bom com regex complexas.
Estou tentando escrever uma regex que encontre apenas os espaços internos de uma String, para que eu possa substituir por um único espaço.
Por exemplo:
// Ao se fazer um replace em:
"Teste de regex"
// deveria retornar:
"Teste de regex"
// Mas se a string for:
" Teste de regex "
//deveria retornar:
" Teste de regex " // sem fazer o trim das pontas
Fazer o replace de todos os espaços sequenciais por um único é tranquilo.
" Teste de regex ".replaceAll("\\s+", " ");
Meu problema é que eu preciso que espaços das pontas sejam ignorados.
Se alguém bom de regex puder me dar uma dica, eu ficaria muito grato 
" Teste de regex ".replaceAll("\\s+", " ").replaceAll ("^\\s+", "").replaceAll ("\\s+$", "")
olá entanglement,
obrigado pela força, mas eu acredito que vc não entendeu o problema.
a sua solução retira os espaços do início/ fim da string tbém (faz o trim).
Eu estou tentando remover os espaços entre palavras da frase sem que os espaços no início e no fim sejam alterados.
Só para exemplificar,
hoje eu faço isso assim:
public class MainClass {
public static void main(String[] args) {
MainClass teste = new MainClass();
String result = teste.middleTrim(" Teste de middle trim ");
System.out.println(result);
}
public String middleTrim(final CharSequence text) {
Pattern LR_SPACE_REGEX = Pattern.compile("^\\s+|\\s+$");
Pattern ANY_SPACE_REGEX = Pattern.compile("\\s+");
// busca espaços nas pontas
Matcher lrMatcher = LR_SPACE_REGEX.matcher(text);
List<Region> lrRegions = new ArrayList<Region>();
while (lrMatcher.find()) {
// mantém as regioes encontradas em ordem decrescente.
lrRegions.add(0, new Region(lrMatcher.start(), lrMatcher.end()));
}
// busca espaços em qquer lugar
Matcher anyMatcher = ANY_SPACE_REGEX.matcher(text);
List<Region> anyRegions = new ArrayList<Region>();
while (anyMatcher.find()) {
// mantém as regioes encontradas em ordem decrescente.
anyRegions.add(0, new Region(anyMatcher.start(), anyMatcher.end()));
}
// exclui os resultados das pontas do resultado "anywhere"
anyRegions.removeAll(lrRegions);
StringBuilder builder = new StringBuilder(text);
// faz a substituicao
for (Region region : anyRegions) {
builder.replace(region.getStart(), region.getEnd(), " ");
}
return builder.toString();
}
static class Region {
private int start;
private int end;
public Region(int start, int end) {
this.start = start;
this.end = end;
}
public int getStart() {
return start;
}
public int getEnd() {
return end;
}
@Override
public int hashCode() {
int hash = 5;
hash = 53 * hash + this.start;
hash = 53 * hash + this.end;
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Region other = (Region) obj;
if (this.start != other.start) {
return false;
}
if (this.end != other.end) {
return false;
}
return true;
}
}
}
que basicamente é uma gambiarra com um pouco de teoria dos conjuntos:
- busco todas as ocorrencias de espaços sequenciais (vou chamar de ANY)
- busco as ocorrencias de espaços sequenciais no início e/ou fim (vou chamar de LR)
- faço a subtração >> ANY - LR = MIDDLE
- então faço o replace (de tras pra frente para nao invalidar as regioes encontradas).
seria interesante se houvesse um jeito de através de uma regex efetuar os passos 1, 2 e 3 de uma forma mais elegante.

Ah, você NÂO quer tirar os espaços das extremidades.
Uma forma trivial de fazer isso (já que escrever expressões regulares que NÂO BATAM com alguma coisa é muito mais difícil que escrever expressões regulares que BATAM com alguma coisa) é guardar os espaços das extremidades, efetuar a troca, e depois repor os espaços.
Eu não recomendaria usar uma expressão regular que NÃO BATA com alguma coisa (que é o caso de usar “(?!X)” ou “(?<!X)” ) porque essas expressões são difíceis de escrever. De qualquer maneira, você pode tentar ver em:
http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html
olá entanglement,
isso mesmo! eu queria apenas normalizar os espaços entre palavras.
esse esquema que vc citou de recolocar os espaços é mais ou menos a idéia que implementei no algoritmo anterior.
só que ao invés de guardar o prefixo e/ou sufixo de espaços, eu guardo as coordenadas e as ignoro na substituição.
funciona. eu só estava tentando melhorá-lo utilizando apenas regex se possível. 
estudando um pouco sobre regex em http://www.regular-expressions.info eu cheguei a essa expressão:
System.out.println(" teste de regex ".replaceAll("(?<=\\S)(\\s+)(?=\\S)", " "));
onde fiz um lookbehind e um lookahead na minha expressão "\s+" procurando por "não espaços", que aparentemente faz o que eu quero.
agora estou analisando se não há alguma situação que esta regex não funcione.