phparraysparsingxbaseclipper

Parse Harbour string array into PHP array


I'm using an ASP.NET web service that returns an Harbour array, it's syntax is:

// single dimensional
{ key1, key2, key3 }

// multi dimensional
{ 
    { key1-value1, key1-value2 }, 
    { key2-value1, key2-value2, key2-value3 },
    { key3-value1, key3-value2 } 
}

Harbour is an updated version of CA-Clipper compiler.

Documentation for Harbour / CA-Clipper language: http://harbourminigui.com/clipperng/ngcd9d.php

Is there any way to parse this string into a PHP array even when the "array" has more than 2 dimensions?


Solution

  • I created a class that can parse this string:

    <?php
    
    namespace Library;
    
    /**
     * @author (odahcam) <luiz@h2k.com.br>
     *
     * @version 1.0.0
     **/
    class Clipper
    {
        public function __construct($argument)
        {
            return;
        }
    
        /**
         * Auxiliar function for self::array().
         *
         * @author odahcam
         *
         * @version 1.0.0
         *
         * @param &{array} $array_string
         *
         * @return {array} $array_php
         **/
        private static function parseArray(&$array_string)
        {
            $array_php = []; // array de saída
            $var_last = ''; // último caractere interpretado
            $key_content = ''; // the content of a $array_php key
    
            foreach ($array_string as $key => $var) {
                /* Deleta o caractere de referencia antes de interpretá-lo.
                 * Isto evita que o caractere seja interpretado duas vezes caso esta
                 * função seja chamada novamente, o que irá acontecer.
                 */
                unset($array_string[$key]);
    
                if ($var_last !== '\\') {
                    switch ($var):
                        case '}':
                        case ',':
                            /* fim de chave ou array.
                             */
                            if ($var_last !== '}' && $var_last !== '{') {
                                $array_php[] = $key_content; // atribui o conteúdo à chave
                                $key_content = ''; // reseta captador de conteúdo de chave
                            }
    
                            switch ($var):
                                case '}':
                                    // logger('retorna array: '.$var.' last: '.$var_last);
                                    /* quebra swicth + foreach porque interpretou um
                                     * array completo, então deve retorná-lo.
                                     */
                                    break 3;
    
                                case ',':
                                    // logger('retorna chave: '.$var.' last: '.$var_last);
                                    /* completou uma chave, então sai dos switchs e
                                     * continua interpretando o array.
                                     */
                                    break 2;
                            endswitch;
    
                            // break;
    
                        case '{':
                            /* inicio de array.
                             */
                            // logger('gerou array: '.$var.' last: '.$var_last);
                            $array_php[] = self::parseArray($array_string); // interpreta o array vigente e armazena em uma chave
                            /* a função executada na linha anterior já faz a remoção
                             * dos caracteres interpretados em $array_string graças
                             * ao operador & (&$array_string).
                             * Aqui só é necessário sair do switch e continuar interpretando
                             * o restante das chaves deste array.
                             */
                            break;
    
                        default:
                            $key_content .= $var;
                            break;
                    endswitch;
                } else {
                    $key_content .= $var;
                }
    
                $var_last = $var; // define o último caractere interpretado.
            }
    
            return $array_php;
        }
    
        /**
         * @author odahcam
         *
         * @version 1.0.0
         *
         * @param {array} $string_user
         *
         * @return {array}
         **/
        public static function matrix($string_user = '{}')
        {
            if (is_string($string_user)) {
                $string_dev = preg_replace('~^{~', '', $string_user); // remove a primeira ocorrência de "{", pois é criada automaticamente.
    
                $string_dev = preg_replace_callback('~(?<!\\\\)([\{\,])[\n\r\s]+~', function ($m) {
                    return $m[1];
                }, $string_dev); // remove espaços antes de "{" e "," e mantém eles.
    
                $string_dev = preg_replace('~[\n\r\s]+(?<!\\\\)(\})~', '}', $string_dev); // remove espaços depois de "}"
    
                // logger($string_dev);
    
                $array_string = str_split($string_dev);
    
                return self::parseArray($array_string);
            } else {
                return $string_user;
            }
        }
    }
    

    Usage:

    var array = \Library\Clipper::matrix(string_array);