Regex Pergunta - Um ou mais espaços fora de um bloco de citação fechado do texto

StackOverflow https://stackoverflow.com/questions/263985

  •  06-07-2019
  •  | 
  •  

Pergunta

Eu quero ser substituir qualquer ocorrência de mais de um espaço com um único espaço, mas não tomar nenhuma ação no texto entre aspas.

Existe alguma maneira de fazer isso com um regex Java? Se assim for, você pode por favor tentar fazê-lo ou me dar uma dica?

Foi útil?

Solução

Aqui está uma outra abordagem, que usa uma visão antecipada para determinar que todas as aspas após a posição atual vêm em pares correspondentes.

text = text.replaceAll("  ++(?=(?:[^\"]*+\"[^\"]*+\")*+[^\"]*+$)", " ");

Se necessário, a antecipação pode ser adaptado a alça escaparam aspas dentro das seções citadas.

Outras dicas

Ao tentar corresponder algo que pode ser contido dentro de outra coisa, ele pode ser útil para criar uma expressão regular que corresponde a ambos, assim:

("[^"\\]*(?:\\.[^"\\]*)*")|(  +)

Isso irá corresponder a uma string ou dois ou mais espaços. Porque as duas expressões são combinadas, ele irá corresponder uma string ou dois ou mais espaços, mas não espaços entre aspas. Usando essa expressão, você terá de analisar cada partida para determinar se ele é uma string ou dois ou mais espaços e agir em conformidade:

Pattern spaceOrStringRegex = Pattern.compile( "(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")|(  +)" );

StringBuffer replacementBuffer = new StringBuffer();

Matcher spaceOrStringMatcher = spaceOrStringRegex.matcher( text );

while ( spaceOrStringMatcher.find() ) 
{
    // if the space group is the match
    if ( spaceOrStringMatcher.group( 2 ) != null ) 
    {
        // replace with a single space
        spaceOrStringMatcher.appendReplacement( replacementBuffer, " " );
    }
}

spaceOrStringMatcher.appendTail( replacementBuffer );

texto entre aspas: As aspas dentro de uma mesma linha ou várias linhas

?

Tokeniza-lo e emitir um único espaço entre tokens. Uma rápida no google para "java tokenizer que lida com aspas" transformaram-se: este link

YMMV

edit: SO não gostava disso link. Aqui está o link de busca google: google . Foi o primeiro resultado.

Pessoalmente, eu não uso Java, mas isso RegExp poderia fazer o truque:

([^\" ])*(\\\".*?\\\")*

Tentando a expressão com RegexBuddy, gera este código, parece-me muito bem:

try {
    Pattern regex = Pattern.compile("([^\" ])*(\\\".*?\\\")*", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
    Matcher regexMatcher = regex.matcher(subjectString);
    while (regexMatcher.find()) {
        for (int i = 1; i <= regexMatcher.groupCount(); i++) {
            // matched text: regexMatcher.group(i)
            // match start: regexMatcher.start(i)
            // match end: regexMatcher.end(i)

            // I suppose here you must use something like
            // sstr += regexMatcher.group(i) + " "
        }
    }
} catch (PatternSyntaxException ex) {
    // Syntax error in the regular expression
}

Pelo menos, parece funcionar bem em Python:

import re

text = """
este  es   un texto de   prueba "para ver  como se comporta  " la funcion   sobre esto
"para ver  como se comporta  " la funcion   sobre esto  "o sobre otro" lo q sea
"""

ret = ""
print text  

reobj = re.compile(r'([^\" ])*(\".*?\")*', re.IGNORECASE)

for match in reobj.finditer(text):
    if match.group() <> "":
        ret = ret + match.group() + "|"

print ret

Depois de analisar o conteúdo citado, executar este sobre o resto, a granel ou peça por peça, conforme necessário:

String text = "ABC   DEF GHI   JKL";
text = text.replaceAll("( )+", " ");
// text: "ABC DEF GHI JKL"

Jeff, você está no caminho certo, mas existem alguns erros no seu código, a saber: (1) Você esqueceu de escapar as aspas dentro das classes de personagens negados; (2) Os parênteses dentro do primeiro grupo de captura deve ter sido a variedade não captura; (3) Se o segundo conjunto de parênteses captura não participa de uma partida, group(2) retorna nulo, e você não está testando para isso; e (4) Se você testar para dois ou mais espaços no regex em vez de um ou mais , você não precisa verificar o comprimento do jogo mais tarde. Aqui está o código revisto:

import java.util.regex.*;

public class Test
{
  public static void main(String[] args) throws Exception
  {
    String text = "blah    blah  \"boo   boo boo\"  blah  blah";
    Pattern p = Pattern.compile( "(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")|(  +)" );
    StringBuffer sb = new StringBuffer();
    Matcher m = p.matcher( text );
    while ( m.find() ) 
    {
      if ( m.group( 2 ) != null ) 
      {
        m.appendReplacement( sb, " " );
      }
    }
    m.appendTail( sb );
    System.out.println( sb.toString() );
  }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top