Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace every character with an element

This is what I have

$str = 'Just a <span class="green">little</span> -text åäö width 123#';

This is what I need

Results in spans and spaces, might be newlines as well.

$result = '<span></span><span></span><span></span><span></span> <span></span> <span class="green"><span></span><span></span><span></span><span></span><span></span><span></span></span> <span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span> <span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span>';

You might wonder what I can possible be needing this for. I want to build a thing where ever character is represented by a block. Will look a bit like Defrag on Windows XP.

Question

  • Replace every character with <span></span>.
  • Do not touch the HTML span that already exists in the string (might be hard?). There can be more than one HTML element.
  • Do not touch spaces and newline.
  • Regexp should do it? or Xpath?

What have I done so far?

I have found articles about the regexp but not replacing every character (excerpt space and newline)

$result = preg_replace("/???/", "<span></span>", $str);
print_r($result);
like image 501
Jens Törnell Avatar asked Apr 30 '13 10:04

Jens Törnell


People also ask

How do you replace all occurrences of a character in a string?

To replace all occurrences of a substring in a string by a new one, you can use the replace() or replaceAll() method: replace() : turn the substring into a regular expression and use the g flag. replaceAll() method is more straight forward.

How do you replace each given character to another?

Approach: Traverse the string. For every i, find the character that needs to be replaced with str[i]. Replace str[i] with that character.

How do you replace all characters in Python?

The replace() method replace() is a built-in method in Python that replaces all the occurrences of the old character with the new character.


3 Answers

You can use preg_replace_callback()

$str = 'Just a <span class="green">little</span> -text åäö width 123#';

function replacement($matches) {
            if (strlen($matches[0]) == 1) 
            {
                return "<span></span>";
            }
            else 
           {
               return $matches[0];
           }
}

$result = preg_replace_callback("~<span.*?<\s*/\s*span>|\S~", "replacement", $str);
print_r($result);

This is just calculate the replacement string dependent on the match. If the length of the match is 1 (a non whitespace character has been found), then replace with the "span" tags, else a span tag has been found, reinsert this.

like image 68
stema Avatar answered Oct 16 '22 13:10

stema


There is no need for hacky regex-solutions. A simple for loop with a state machine should do just fine:

define('STATE_READING', 1);
define('STATE_TAG', 2);

$str = 'Just a <span class="green">little</span> -text åäö width 123#';
$result = '';

$state = STATE_READING;
for($i = 0, $len = strlen($str); $i < $len; $i++) {
    $chr = $str[$i];

    if($chr == '<') {
        $state = STATE_TAG;
        $result .= $chr;
    } else if($chr == '>') {
        $state = STATE_READING;
        $result .= $chr;
    } else if($state == STATE_TAG || strlen(trim($chr)) === 0) {
        $result .= $chr;
    } else {
        $result .= '<span></span>';
    }
}

This loop is just keeping track if we are reading a tag or a single character. If it is a tag (or whitespace), append the actual character, otherwise append <span></span>.

Results in:

<span></span><span></span><span></span><span></span> <span></span> <span class="green"><span></span><span></span><span></span><span></span><span></span><span></span></span> <span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span><span></span><span></span> <span></span><span></span><span></span><span></span>
like image 37
alexn Avatar answered Oct 16 '22 14:10

alexn


is it a requirement to use only one regular expression?

if not - you could replace substring which you need to safe with some unique character, execute replacing by regexp, put substring instead of that unique char.

Just like this:

$str2 = str_replace('<span class="green">little</span>', '$', $str);
$str3 = preg_replace("/([^\s\n\$])/", "<span></span>", $str2);
$result = str_replace('$', '<span class="green">little</span>', $str3);

see live demo http://codepad.viper-7.com/7wu9fd

UPD:

Perhaps it should be considered just as hint. My suggestion was to store substring(s) what needed to be stored, replace everything you need, put stored values back into string.

$str = 'Just a <span class="green">little</span> -text åäö width 123#';

preg_match_all('/<[^>]+>/', $str, $matches);
$storage=array();
for($i=0, $n=count($matches[0]); $i<$n; $i++)
{
    $key=str_repeat('$', $i+1);
    $value=$matches[0][$i];
    $storage[$key]=$value;
    $str=str_replace($value, $key, $str);
}
$storage=array_reverse($storage);

$str = preg_replace("/([^\s\n\$])/", "<span></span>", $str);
foreach($storage as $k=>$v)
{
    $str=str_replace($k, $v, $str);
}
echo htmlspecialchars($str);

working demo is there http://codepad.viper-7.com/L4YZOz

like image 1
Ruslan Polutsygan Avatar answered Oct 16 '22 13:10

Ruslan Polutsygan