Estoy tratando de mantener un paréntesis dentro de una cadena que está rodeada por un paréntesis.

La cadena en cuestión es: test (blue,(hmmm) derp)

El resultado deseado en una matriz es: test y (blue,(hmmm) derp).

El resultado actual es: (blue,, (hmm) y derp).

Mi código actual es el de esto:

var input = Regex
  .Split(line, @"(\([^()]*\))")
  .Where(s => !string.IsNullOrEmpty(s))
  .ToList();

¿Cómo puedo extraer el texto dentro de los paréntesis externos (manteniéndolos) y mantener el paréntesis interno como una cadena en una matriz?

EDITAR:

Para aclarar mi pregunta, quiero ignorar los paréntesis internos y solo dividir en los paréntesis externos.

herpdediderp (orange,(hmm)) some other crap (red,hmm)

Debe convertirse en:

herpdediderp, orange,(hmm), some other crap y red,hmm.

El código funciona para todo excepto los paréntesis dobles: (orange,(hmm)) a orange,(hmm).

2
7h3w1z4rd 24 feb. 2018 a las 02:57

3 respuestas

Creo que si piensas en el problema al revés, se vuelve un poco más fácil: no te diviertas en lo que no haces, extrae lo que quieres.

La única parte un poco complicada si coincide con paréntesis anidados, supongo que solo irás un nivel más profundo.

El primer ejemplo:

var s1 = "(blue, (hmmm) derp)";
var input = Regex.Matches(s1, @"\((?:\(.+?\)|[^()]+)+\)").Cast<Match>().Select(m => Regex.Matches(m.Value, @"\(\w+\)|\w+").Cast<Match>().Select(m2 => m2.Value).ToArray()).ToArray();
// input is string[][] { string[] { "blue", "(hmmm)", "derp" } }

El segundo ejemplo usa un método de extensión:

public static string TrimOutside(this string src, string openDelims, string closeDelims) {
    if (!String.IsNullOrEmpty(src)) {
        var openIndex = openDelims.IndexOf(src[0]);
        if (openIndex >= 0 && src.EndsWith(closeDelims.Substring(openIndex, 1)))
            src = src.Substring(1, src.Length - 2);
    }
    return src;
}

El código / patrones son diferentes porque los dos ejemplos se manejan de manera diferente:

var s2 = "herpdediderp (orange,(hmm)) some other crap (red,hmm)";
var input3 = Regex.Matches(s2, @"\w(?:\w| )+\w|\((?:[^(]+|\([^)]+\))+\)").Cast<Match>().Select(m => m.Value.TrimOutside("(",")")).ToArray();
// input2 is string[] { "herpdediderp", "orange,(hmm)", "some other crap", "red,hmm" }
0
NetMage 27 feb. 2018 a las 18:50

Esperemos que a alguien se le ocurra una expresión regular. Aquí está mi código de respuesta.

static class ExtensionMethods
{
    static public IEnumerable<string> GetStuffInsideParentheses(this IEnumerable<char> input)
    {
        int levels = 0;
        var current = new Queue<char>();
        foreach (char c in input)
        {
            if (levels == 0)
            {
                if (c == '(') levels++;
                continue;
            }
            if (c == ')')
            {
                levels--; 
                if (levels == 0)
                { 
                    yield return new string(current.ToArray()); 
                    current.Clear();
                    continue;
                }
            }
            if (c == '(')
            {
                levels++; 
            }
            current.Enqueue(c); 
        }
    }
}

Programa de prueba:

public class Program
{
    public static void Main()
    {

        var input = new []
        {
            "(blue,(hmmm) derp)", 
            "herpdediderp (orange,(hmm)) some other crap (red,hmm)"
        };

        foreach ( var s in input )
        {
            var output = s.GetStuffInsideParentheses();
            foreach ( var o in output )
            {
                Console.WriteLine(o);
            }
            Console.WriteLine();
        }
    }
}

Salida:

blue,(hmmm) derp

orange,(hmm)
red,hmm

Código en DotNetFiddle

1
John Wu 24 feb. 2018 a las 19:18

Puedes usar el método

public string Trim(params char[] trimChars)

Así

string trimmedLine = line.Trim('(', ')'); // Specify undesired leading and trailing chars.

// Specify separator characters for the split (here command and space):
string[] input = trimmedLine.Split(new[]{',', ' '}, StringSplitOptions.RemoveEmptyEntries);

Si la línea puede comenzar o finalizar con 2 paréntesis consecutivos, use simplemente buenas declaraciones if antiguas:

if (line.StartsWith("(")) {
    line = line.Substring(1);
}
if (line.EndsWith(")")) {
    line = line.Substring(0, line.Length - 1);
}
string[] input = line.Split(new[]{',', ' '}, 
4
Olivier Jacot-Descombes 24 feb. 2018 a las 15:00