Katie
Katie

Reputation: 2693

PHP wordwrap and non-printing strings

I am stuck, stuck, stuck.

I am writing a class that needs a method and I can’t find a solution that completely passes all the unit tests I wrote, there are small gotchas with each solution.

The method is wrapping text (but with a catch) and has three parameters:

For example, if there is a set of markup strings [“!!”,”<lime>”] (they can be anything), and the text “This is a !!word!!! and this is some <lime>fruit<lime>.” Wordwrap it to a width of let’s say 25 characters:

1234567890123456789012345
This is a word and this 
is some fruit.

That would be the proper wrapping, but in order for wordwrap to work, I have to remove the markup and run PHP's wordwrap (which places \n's into the text string appropriately), then return the markup for later processing.

So, here is the problem, I would much rather use php’s wordwrap function than roll my own, as best practice. Here are the solutions that I have tried so far, but failed the unit tests in small ways:

I was starting down the road of keeping two strings, the stripped and original, then marching down each string to rebuild the original, but that seems...ugly. Which leads me to believe that I must be missing something.

Any ideas?

Here is the second solution helper functions for stripping and replacing:

/** * Takes the text and replaces all markup and store the markup and * their positions in markupInText for later use * * @param $text * @return string - the text with all the markup switched to /a */ public function stripMarkup($text) {

// if there are any markups
if ($this->markupStyles) {


    // get all the markups
    $markups = array_keys($this->markupStyles);

    // go through each markup
    foreach ($markups AS $nextMarkup) {

        // search through the string
        $offset = 0;

        // search for the next markup
        while (($pos = strpos($text, $nextMarkup, $offset)) !== false) {

            // add the position to the array of position for the markup
            $this->markupInText[$nextMarkup][] = $pos;

            // move the offset as far as the next markup
            $offset = $pos + strlen($nextMarkup);
        }
    }

    // strip out the markup
    foreach ($markups AS $nextMarkup) {

        // replace each string with blank
        $text = str_replace($nextMarkup,"",$text);
    }
}

return $text;

}

/**
 * Return the markup that was stripped of markup to its former glory
 * @param $text
 * @return string - the restored text
     */

public function returnMarkup($text) {


// go through each markup
foreach ($this->markupInText AS $markup => $posArray) {

    // go through the range of positions
    foreach ($posArray AS $pos) {

        // put back the markup
        $text = substr($text,0,$pos) . $markup . substr($text,$pos);

    }


}

// reset the markup in text
$this->markupInText = [];

// return the restored text
return $text;

}

// part of the suite of test cases that fails:

        $original = "This<red> is<red> !s!o!m!e text.";
        $answer = $markup->stripMarkup($original);
        $this->assertSame("This is some text.",$answer);
        $answer = $markup->returnMarkup($answer);
        $this->assertSame($original, $answer);

// phpunit failure
Failed asserting that two strings are identical.
Expected :This<red> is<red> !s!o!m!e text.
Actual   :This <red>is <red>some text.!!!!

Upvotes: 0

Views: 147

Answers (1)

Unix One
Unix One

Reputation: 1181

Getting better, but the positions I am storing are relative, meaning as I start to restore the markup values, the string is stretching and the position values aren’t valid

If you store them in their absolute positions in the original string, then you can recursively (i.e. after updating new string each time) add them back in their original positions. The only thing you'd have to account for would be the newly added \n characters by wordwrap. Assuming that the original string didn't contain any newline characters, while inserting, you would also count the number of \ns occurrences up to the positions you're inserting in and recalculate rest of the insertion points by adding that number.

Upvotes: 1

Related Questions