用一个元素替换每个字符。

[英]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.

你可能想知道我为什么需要这个。我想构建一个用block表示的东西。看起来有点像Windows XP上的Defrag。

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.
  • 不要触摸已经存在于字符串中的HTML span(可能很难)。可以有多个HTML元素。
  • Do not touch spaces and newline.
  • 不要接触空格和换行。
  • Regexp should do it? or Xpath?
  • Regexp应该做的吗?或Xpath吗?

What have I done so far?

到目前为止我做了什么?

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

我找到了关于regexp的文章,但没有替换每个字符(摘录空格和换行)

$result = preg_replace("/???/", "<span></span>", $str);
print_r($result);

7 个解决方案

#1


1  

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

不需要hacky regex解决方案。一个简单的带有状态机的for循环应该做得很好:

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>

#2


2  

You can use preg_replace_callback()

您可以使用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.

这只是根据匹配计算替换字符串。如果匹配的长度为1(找到了一个非空白字符),然后用“span”标记替换,否则将找到一个span标记,重新插入这个标记。

#3


1  

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.

如果没有,您可以用某个惟一字符替换需要保护的子字符串,执行regexp替换,将子字符串替换为惟一字符。

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

看到现场演示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

工作演示在那里http://codepad.viper-7.com/L4YZOz

#4


0  

While this is probably possible with a regex, but I'd go with a loop. Example code below is for single-byte character sets but can be modified for multi-byte (e.g. UTF-16) or variable-byte (e.g. UTF-8) character set.

虽然使用regex可能实现这一点,但我将使用循环。下面的示例代码用于单字节字符集,但可以修改为多字节(如UTF-16)或可变字节(如UTF-8)字符集。

$input = 'Just a <span class="green">little</span> -text åäö width 123#';
$output = '';
$length = strlen($input);
$i = 0;
$matches = array(); // preg_match variable
// While for finer control
while($i < $length) {
    // Check for start of span tag, check for < character first for speed-up
    if($input[$i] == "<" && preg_match("#<span[^>]*>.*</span>#siU", substr($input, $i), $matches) == 1) {
        // Skip the span tag
        $i = $i + strlen($matches[0]);
        $output .= $matches[0];
    } else {
        $output .= "<span></span>";
        $i++;
    }
}

Working example

工作示例

#5


0  

So here's what I came up with using preg_replace_callback():

下面是我使用preg_replace_callback()得出的结果:

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

// This requires PHP 5.3+
$output = preg_replace_callback('#.*?(<span[^>]*>.*?</span>)|.*#is', function($m){
    if(!isset($m[1])){return preg_replace('/\S/', '<span></span>', $m[0]);}
    $array = explode($m[1], $m[0]);
    $array = preg_replace('/\S/', '<span></span>', $array);
    return(implode($m[1], $array));
}, $str);
echo($output);

Output:

输出:

<span></span><span></span><span></span><span></span> <span></span> <span class="green">little</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>aaa</span> <span></span><span></span><span></span>

#6


0  

Bit of a hack but try this:

有点像黑客,但试试这个:

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

// get all span tags
if(preg_match_all("/(\<span.*\<\/span\>)/", $str, $matches))
{
    // replace spans with #
    $str=preg_replace_all("/(\<span.*\<\/span\>)/", "#", $str);

    //print_r($matches);
}
// replace all non spaces, CR and #
$str=preg_replace("/[^\s\n#]/", "<span></span>", $str);
// replenish the matched spans
while(list($key,$value)=each($matches[0]))
{
    $str=preg_replace('/#/', $value, $str, 1);
}

#7


0  

This is NOT a hacky regex method. This is a solid, concise, one-line-one-function-call solution that avoids having to iterate a battery of conditions on each character in a string, preserves tags, and cares for multi-byte characters.

这不是一种陈腐的regex方法。这是一个可靠的、简洁的、单行函数调用的解决方案,它避免了对字符串中的每个字符重复一系列的条件、保留标记和关注多字节字符。

alexn's solution does not maintain the visible character length of åäö. His solution will print 6 opening and closing span tags to screen instead of just 3. This is because mb_ functions are not used. On this topic, be wary of any methods on this page that are not using mb_ prefixed string functions.

alexn的解决方案没有保持aao的可见字符长度。他的解决方案将打印6个打开和关闭跨度标签到屏幕上,而不是仅仅3个。这是因为不使用mb_函数。在这个主题上,请注意本页上没有使用mb_前缀字符串函数的任何方法。

My suggested solution will leverage the (*SKIP)(*FAIL) technique to ignore/disqualify all encountered tags and then only match non-white-space characters in the string.

我建议的解决方案将利用(*SKIP)(*FAIL)技术来忽略/取消所有遇到的标记,然后只匹配字符串中的非空白字符。

Code: (Demo)

代码:(演示)

$str = 'Just a <span class="green">little</span> -text åäö width 123#';
var_export(preg_replace('/<[^>]*>(*SKIP)(*FAIL)|\S/','<span></span>',$str));  // no "u" flag means åäö will be span x6
echo "\n";
var_export(preg_replace('/<[^>]*>(*SKIP)(*FAIL)|\S/u','<span></span>',$str)); // "u" flag means åäö will be span x3

Output: (scroll right to see the impact of the unicode flag on the pattern)

输出:(向右滚动可以看到unicode标记对模式的影响)

'<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>'
// notice the number of replacements for åäö ->-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------111111111111122222222222223333333333333444444444444455555555555556666666666666
'<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>'
// notice the number of replacements for åäö ->-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------111111111111122222222222223333333333333
智能推荐

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:http://www.itdaan.com/blog/2013/04/30/3a6bb1b91aeea30624e749e53eb40174.html



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告