Remova os espaços entre colchetes, exceto para o texto entre aspas

Aug 19 2020

Estou procurando um regex que pode remover espaços quando eles estão entre colchetes correspondentes, ou seja , (e ), exceto quando há espaços entre aspas ( 'ou ") dentro dos colchetes.

Atualmente tenho o regex \s+(?=[^(]*\)), que remove todos os espaços encontrados entre colchetes. O mesmo ocorre quando há espaços entre aspas.

// My input
do something with(in = 1, text='some text with spaces' , text2="also has spaces")

// My current output
do something with(in=1,text='sometextwithspaces',text2="alsohasspaces")

// My desired output
do something with(in=1,text='some text with spaces',text2="also has spaces")

Além disso:

  • As aspas só podem ser encontradas dentro dos colchetes
  • Pode haver "em ' 'texto:, text='text with " inside'sem o \caractere de escape.
  • Pode haver 'em " "texto:, text="text with ' inside"sem o \caractere de escape.
  • Não caractere de escape antes das aspas na string:text='This is \" not there'

Eu sei que existem algumas perguntas sobre os padrões de regex, mas não consegui encontrar uma que resolvesse o problema. Entre as muitas coisas que tentei foi olhar para a frente para encontrar apenas coisas entre (até 'ou "com \s+(?=[^("]*[\)"]), mas que ainda encontra os espaços entre "e ".

Alguém pode me apontar na direção certa?

Respostas

1 AbdessabourMtk Aug 19 2020 at 19:06

Fiz algumas modificações na expressão regular que você usou:

# match a space or more 
# if the fol
(?<!['"][^,]*)\s+(?=[^(]*\))|\s+(?![^,]*['"])(?=[^(]*\))

a expressão regular é dividida em duas partes, a expressão regular corresponderá a uma delas:

  1. a primeira parte (?<!['"][^,]*)\s+(?=[^(]*\))corresponde ao máximo de espaço em branco possível \s+que não seja precedido por aspas '"( (?<!['"][^,]*)) e se apenas for seguido por um parêntese de fechamento.(?=[^(]*\))
  2. a segunda parte \s+(?![^,]*['"])(?=[^(]*\))corresponde ao máximo de espaço em branco possível \s+que não (?![^,]*['"])seja seguido por uma aspa e somente se for seguido por um parêntese de fechamento (?=[^(]*\)).

você pode testar aqui

2 DmitryBychenko Aug 19 2020 at 02:27

Bem, já que você tem dois tipos de citações, "e 'você tem que lidar com a citação de citação :

  abc"def pqr' ijk" "klm ' xyz"

Observe que ambos os apóstrofos são enquotados e é por isso que não funcionam. Mesmo com colchetes . Duvido que uma simples expressão regular possa ajudar aqui, mas Finite State Machine pode:

private static string RemoveSpaces(string value) {
  if (string.IsNullOrEmpty(value))
    return value;

  bool inQuotation = false;
  bool inApostroph = false;
  int bracketCount = 0;
  int escapeCount = 0;
  StringBuilder result = new StringBuilder(value.Length);

  foreach (char c in value) {
    if (inQuotation) {
      result.Append(c);
      inQuotation = c != '"' || (escapeCount % 2 != 0);
    }
    else if (inApostroph) {
      result.Append(c);
      inApostroph = c != '\'' || (escapeCount % 2 != 0);
    }
    else {
      if (c != ' ' || bracketCount <= 0)
        result.Append(c);

      if (c == '(')
        bracketCount += 1;
      else if (bracketCount == ')')
        bracketCount -= 1;

      inQuotation = c == '"' && (escapeCount % 2 == 0);
      inApostroph = c == '\'' && (escapeCount % 2 == 0);
    }

    escapeCount = c == '\\' ? escapeCount + 1 : 0;
  }
  return result.ToString();
}

Demo:

string test =
  @"do something with(in = 1, text='some text with spaces' , text2=""also has spaces"")";

Console.WriteLine(RemoveSpaces(test));

Resultado:

do something with(in=1,text='some text with spaces',text2="also has spaces")