es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo compaginar una coma fuera de múltiples paréntesis mediante regex

Divido una cadena por comas, pero no dentro de paréntesis, usando preg_split. He creado el siguiente código:

preg_split('#,(?![^\(]*[\)])#', $str);

que funciona perfectamente a menos que haya una coma antes de un paréntesis anidado.

Funciona para:

$str = "first (1,2),second (child (nested), child2), third";

Array
(
    [0] => first (1,2)
    [1] => second (child (nested), child2)
    [2] => third
)

pero no funciona para:

$str = "first (1,2),second (child, (nested), child2), third";

Array
(
    [0] => first (1,2)
    [1] => second (child
    [2] => (nested), child2)
    [3] => third
)
Tags:  , ,

Answer

  1. Avatar for davy.ai

    Solución para dividir una cadena por comas, pero no dentro de paréntesis

    Como experto en TI especializado en PHP, regex y preg-split, la siguiente expresión regular se puede utilizar para dividir una cadena por comas, pero no dentro de paréntesis:

    preg_split('#,(?![^(\)]*(?:\(|\)))#', $str);
    

    Esta expresión regular utiliza “negative lookahead” para asegurarse de que la coma no está seguida de cualquier número de caracteres que no sean paréntesis, seguidos de un paréntesis de apertura, seguidos de cualquier número de caracteres que no sean paréntesis, seguidos de un paréntesis de cierre.

    Esta solución funciona perfectamente en la mayoría de los casos, pero puede haber problemas cuando hay una coma antes de un paréntesis anidado. En esos casos, es posible que la expresión regular no funcione como se espera.

    Por ejemplo, en la siguiente cadena:

    $str = "first (1,2),second (child, (nested), child2), third";
    

    La expresión regular produciría la siguiente salida:

    Array (
      [0] => first (1,2)
      [1] => second (child
      [2] => (nested), child2)
      [3] => third
    )
    

    Como podemos ver, la expresión regular ha dividido la cadena en la coma antes del paréntesis anidado, lo cual no es lo que queremos.

    Para superar este problema, podemos utilizar una expresión regular más avanzada que tenga en cuenta los paréntesis anidados. Una solución es utilizar la extensión tokenizer en PHP, que puede tokenizar una cadena en tokens individuales según un conjunto de reglas.

    Aquí tienes un ejemplo de cómo podemos utilizar la extensión tokenizer para dividir una cadena por comas, pero no dentro de paréntesis, incluyendo paréntesis anidados:

    $tokens = token_get_all('<?php ' . $str);
    $result = [];
    $buffer = '';
    $paren_count = 0;
    
    foreach ($tokens as $token) {
      if (is_array($token)) {
        if ($token[0] === T_OPEN_PARENTHESIS) {
          $buffer .= $token[1];
          $paren_count++;
        } else if ($token[0] === T_CLOSE_PARENTHESIS) {
          $buffer .= $token[1];
          $paren_count--;
        } else if ($paren_count === 0 && $token[0] === T_COMMA) {
          $result[] = trim($buffer);
          $buffer = '';
        } else {
          $buffer .= $token[1];
        }
      } else {
        $buffer .= $token;
      }
    }
    
    if (!empty($buffer)) {
      $result[] = trim($buffer);
    }
    
    print_r($result);
    

    En esta solución, primero tokenizamos la cadena utilizando la función token_get_all() en PHP. Esto tokeniza la cadena en tokens individuales según las reglas de sintaxis de PHP.

    Luego recorremos cada token y llevamos un contador de paréntesis abiertos utilizando una variable $paren_count. Si encontramos un paréntesis de apertura, incrementamos $paren_count. Si encontramos un paréntesis de cierre, decrementamos $paren_count. Si $paren_count es cero y encontramos una coma, sabemos que podemos dividir la cadena en ese punto.

    También llevamos un registro de una variable $buffer, que almacena el/los token(s) actual(es) que estamos agregando. Continuamos agregando al buffer hasta encontrar una coma que no esté dentro de ningún paréntesis. En ese punto, añadimos el buffer al array de resultados y comenzamos de nuevo con un buffer vacío.

    Esta solución produce la salida deseada para nuestra cadena de ejemplo:

    Array (
      [0] => first (1,2)
      [1] => second (child, (nested), child2)
      [2] => third
    )
    

    Como podemos ver, la solución divide correctamente la cadena por comas pero mantiene los paréntesis anidados intactos.

Comments are closed.