phpregexlatex

How can I check when there are only opening or closing quotes in PHP to make replacements?


In a text that comes with a separator, I need to create several paragraphs for a document written in LaTeX. The purpose of this code is to replace any content within quotes with \textquote{the text}

Let's assume the following text:

$str="Irán pueblos numerosos diciendo: «Vamos a subir al monte del Señor, al templo del Dios de Jacob».|Él nos enseñará sus caminos y caminaremos por sus sendas.|Viene el Mesías, el Cristo; cuando venga, nos hará saber todas las cosas.";

I need to create the following content:

\fourargs
{Irán pueblos numerosos diciendo: \textquote{Vamos a subir al monte del Señor, al templo del Dios de Jacob}.}
{%
Él nos enseñará sus caminos y caminaremos por sus sendas.%
}{%
Viene el Mesías, el Cristo; cuando venga, nos hará saber todas las cosas.%
}{%
Él nos enseñará sus caminos y caminaremos por sus sendas.%
}
    

I can achieve this with the following code without any problem:

DEMO

$str="Irán pueblos numerosos diciendo: «Vamos a subir al monte del Señor, al templo del Dios de Jacob».|Él nos enseñará sus caminos y caminaremos por sus sendas.|Viene el Mesías, el Cristo; cuando venga, nos hará saber todas las cosas.";    
$html="";
$break=PHP_EOL."\t";
$quotes=["/'(.*?)'/",'/"(.*?)"/',"/«(.*?)»/","/“(.*?)”/"];
$textquote="\\textquote{\$1}";                  
$fourArgs="
\\fourargs
    {%s}
    {%%
        %s%%
    }{%%
        %s%%
    }{%%
        %s%%
    }";
$tmp=explode('|',preg_replace($quotes,$textquote,$str));
$html.=sprintf($fourArgs,
           $tmp[0],
           $tmp[1],
           $tmp[2],
           $tmp[1]
       );
echo $html;

My problem arises when the opening and closing quotes are placed in different groups when doing the explode. In that case, the replacement with textquote{...} does not work as expected.

Suppose the following code:

DEMO

The content of $str is as follows:

$str="Irán pueblos numerosos diciendo: «Vamos a subir al monte del Señor, al templo del Dios de Jacob.|Él nos enseñará sus caminos y caminaremos por sus sendas».|Viene el Mesías, el Cristo; cuando venga, nos hará saber todas las cosas.";    

The final result is as follows:

\fourargs
    {Irán pueblos numerosos diciendo: \textquote{Vamos a subir al monte del Señor, al templo del Dios de Jacob.}
    {%
        Él nos enseñará sus caminos y caminaremos por sus sendas}.%
    }{%
        Viene el Mesías, el Cristo; cuando venga, nos hará saber todas las cosas.%
    }{%
        Él nos enseñará sus caminos y caminaremos por sus sendas}.%
    }

But the expected result is:

\fourargs
    {Irán pueblos numerosos diciendo: \textquote{Vamos a subir al monte del Señor, al templo del Dios de Jacob}.}
    {%
        \textquote{Él nos enseñará sus caminos y caminaremos por sus sendas}.%
    }{%
        Viene el Mesías, el Cristo; cuando venga, nos hará saber todas las cosas.%
    }{%
        \textquote{Él nos enseñará sus caminos y caminaremos por sus sendas}.%
    }

How could I achieve the expected result in all cases?


Solution

  • Preprocess your string before your replacement like that:

    $str = 'Irán … diciendo: «Vamos … Jacob.|Él nos … sendas».|Viene el … cosas.';
    
    $pattern = <<<'REGEX'
    ~
    (?<open> ' ) .*? (?<close> ' ) |
    (?<open> " ) .*? (?<close> " ) |
    (?<open> « ) .*? (?<close> » ) |
    (?<open> “ ) .*? (?<close> ” )
    ~Jux
    REGEX;
    
    $replacement = fn($m) => str_replace('|', "{$m['close']}|{$m['open']}", $m[0]);
    
    echo preg_replace_callback($pattern, $replacement, $str);
    
    // Irán … diciendo: «Vamos … Jacob.»|«Él nos … sendas».|Viene el … cosas.
    

    Pattern variant that uses the first character discrimination and a branch reset group:

    $pattern = <<<'REGEX'
    ~
    (?=['"«“])
    (?|  (?<open> ' ) .*? (?<close> ' )
      |  ( " ) .*? ( " )
      |  ( « ) .*? ( » )
      |  ( “ ) .*? ( ” )
    )
    ~ux
    REGEX;
    

    Pro: the pattern fails quickly on useless positions (positions without a quote) without to test each branch.

    Note that in a branch reset group, you only have to define the names of capture groups in the first branch to set them automatically in other branches.


    About your formatted string, you can also write it like that:

    $fourArgs = '
    \\fourargs
        {%s}
        {%%
            %s%%
        }{%%
            %s%%
        }{%%
            %2$s%%
        }';
    
    // ...
    
    $html .= vsprintf($fourArgs, $tmp);