PHP: Replace only the first word repeated [closed]

0

Hello, for example, I have the phrase:

  

My name is "Vitor", the name "his" "is" "Vitor", "his" name is "" Victor "

I use a preg_replace to change all words that are surrounded by the word "pineapple". I would stay:

  

My name is "pineapple", the name "pineapple" "pineapple" "pineapple", "pineapple" name "pineapple" "pineapple"

However, how can I perform this replace only on the first repeated words that are enclosed in quotation marks? Example:

  

My name is "pineapple", the name "pineapple" "pineapple" "Vitor", "pineapple" name "is" "Vitor"

Thank you.

    
asked by anonymous 05.06.2017 / 06:07

1 answer

0

It may have a specific function for this, but it's easy to do at hand.

Supposing the text:

  

My name is "Vitor", the name "his" "is" "Vitor", "his" name is "" Victor "

We can simply do:

Find " , finding get the word up to the next " . This word check if it has been previously replaced, if not replace and add this word in the "already replaced" list.

This is more for educational purposes, but you can clearly do this in a more organized way.

$substituto = "abacaxi";

$posicaoInicio = -1;
$posicaoFim = -1;
$dicionario = [];


while($posicaoInicio !== false && $posicaoFim !== false){

    $posicaoInicio = strpos($texto, '"', $posicaoFim + 1);
    $posicaoFim = strpos($texto, '"', $posicaoInicio + 1);

    $palavraTamanho = ($posicaoFim - $posicaoInicio) - 1;
    $palavra = substr($texto, $posicaoInicio + 1, $palavraTamanho);

    if($posicaoInicio !== false 
       && $posicaoFim !== false 
       && in_array($palavra, $dicionario, true) === false){

        $dicionario[] = $palavra;

        $texto = substr_replace($texto, $substituto, $posicaoInicio + 1, $palavraTamanho);

        $diferencaTamanho = strlen($substituto) - $palavraTamanho;
        $posicaoFim = ($posicaoFim + $diferencaTamanho) + 1;

    }

}

Try this.

The idea is very simple, we first find the beginning and end of the target word, that is the word that is between the quotation marks, for this we use:

 $posicaoInicio = strpos($texto, '"', $posicaoFim + 1);
 $posicaoFim = strpos($texto, '"', $posicaoInicio + 1);

The strpos will find the first occurrence from the offset, so assuming:

  

My name is "Vitor"

The first quotation mark (beginning) is 12, so we need to search for another from 13, which will be found in position 18.

We then know that the first word is between the 13th through the 17th byte, in this case . Logic, we need to exclude quotes, for this we use:

$palavraTamanho = ($posicaoFim - $posicaoInicio) - 1;

This will be used for 18 - 12 (= 6), then subtract 1, making 5. That is the size of the word.

Then we get the word:

$palavra = substr($texto, $posicaoInicio + 1, $palavraTamanho);

The beginning is 12, but 12 includes the quotation marks, so we have to add 1, thus taking the 5 bytes, corresponding to Vitor , without quotation marks.

Now we need to know if the word exists and if it has not already been replaced, then:

$posicaoInicio !== false 
&& $posicaoFim !== false 
&& in_array($palavra, $dicionario, true) === false

This will cause it to have found the two quotation marks and the word can not be inserted in $dicionario , which is an array that we will fill with the words already replaced. That is, all the words we already know (which is in the dictionary) have already been changed. ;)

If it's all right and has not been replaced do this. We added the word in our dictionary:

$dicionario[] = $palavra;

Now we change the word in the text using:

$texto = substr_replace($texto, $substituto, $posicaoInicio + 1, $palavraTamanho);

This will cause you to insert insert pineapple from the 13th byte with a 5-digit size. That is, it will change Vitor to abacaxi , it will remove Vitor and add abacaxi instead.

If you notice, there is a problem, abacaxi is larger in amount of characters, than Vitor , so we need to calculate $posicaoFim , after all we need to know the last quotation mark.

So we use:

$diferencaTamanho = strlen($substituto) - $palavraTamanho;
$posicaoFim = ($posicaoFim + $diferencaTamanho) + 1;

This will calculate the difference in the size of both texts ( Vitor and abacaxi ) and will adjust the last " . Mathematically the difference between the two is 7 - 5 (= 2). Then we need to count the quotes, adding 1, in total it will be 18 + 2 + 1 (= 21). The last check is in 21st position.

Now, we do this again, but with dele , and so on.

05.06.2017 / 09:31