PHP需要计算字符串中一个序列中相同字符的数量


PHP need to count the number of same characters in a sequence in a string

我正在使用php将文本服务器端合并到rtf格式的文件中。我的字段由文件不同部分的波浪号序列标识。每个序列都有不同的长度。为了使用substr_replace将字段替换为合并材质,我需要计算波浪号序列的长度。我可以找到第一个波浪号没有问题使用:

$firsttilde=strpos($filedata,'~',$currentposinfile);

其中(在此代码中)$filedata是包含文件内容的字符串,$currentposinfile是我搜索的起点。我的问题是,我找不到一个函数可以计算序列中相同字符的数量。

$filedata的第一个波浪号开始,我看到的部分看起来是这样的(换句话说,波浪号序列):

"~~~~~~"

我已经尝试过strrpos来查找最后一个波浪号,但这是在$filedata的后面部分中查找包含波浪号的字段。我所想做的就是从字符串中我所知道的位置开始计算波浪号的数量,但我找不到任何函数来做这件事。不过肯定有一个。

您可以将preg_match_allPREG_OFFSET_CAPTURE标志结合使用。这将保存在matches变量中找到字符串的偏移量,允许您同时找到字符串及其偏移量。

$matches = Array();
preg_match_all( '/~+/', $input, $matches, PREG_OFFSET_CAPTURE);
foreach( $matches[0] as $k => $v ) {
  $length = strlen( $v[0] );
  echo "Found a string '"{$v[0]}'" beginning at {$v[1]} with length {$length}<br>";
}

对于下方的示例文本

$input = <<<TEXT
this is
~~~~~~~~
quite something
~~~~
TEXT;

输出将是:

Found a string "~~~~~~~~" beginning at 8 with length 8
Found a string "~~~~" beginning at 34 with length 4

这使用for迭代来检查文本中的字符。它是preg_match()解决方案的替代方案,后者更紧凑。

<?php
$text = <<<'TEXT'
abc
~~~
def
~~~~~~
123
~~~~~~~~~~
TEXT;
//$currentposinfile = 0;
//$firsttilde = strpos($text,'~',$currentposinfile);
//$text = substr($text, $firsttilde);
$sequenceStarted = false;
$sequenceLength = 0;
$textLength = strlen($text);
for ($i = 0; $i <= $textLength; $i++) {
    $char = $text[$i]; 
    //echo 'Char ' . $char . '  at ' . $i . PHP_EOL;
    if($char === '~') {
        // found start of a sequence
        if($sequenceStarted === false) {
           $sequenceLength++;      
           $sequenceStarted = true;      
           $sequenceStartPosition = $i;
        } 
        // it's a char in sequence               
        continue;
    }
    // found first char out of sequence
    if($char !== '~' && $sequenceStarted === true) {
         $sequenceStarted = false;
         $sequenceEndPostion = $i - 1;
         $sequenceLength = $i - $sequenceStartPosition;
         echo 'Found a sequence of length: ' .  $sequenceLength . ' starting at '.$sequenceStartPosition.' ending at ' . $sequenceEndPostion . '.' . PHP_EOL;
         #break;
         $sequenceLength = 0; $sequenceEndPostion = 0;
    }
}

结果:

Found a sequence of length: 3 starting at 5 ending at 7.
Found a sequence of length: 6 starting at 15 ending at 20.
Found a sequence of length: 10 starting at 28 ending at 37.

如果您已经有了序列块,您可以简单地使用count_chars()。

<?php
$text = 'ABC~~~123';
$data = count_chars($text, 1);
echo 'The string "'. $text .'" contains the char "~" '. $data[126] . ' times.';

$data[126]=将ASCII代码126用于~

结果:字符串"ABC~~~123"包含字符"~"3次。

演示:https://eval.in/204882

以下函数将循环遍历字符串并返回匹配数组:

function findSequences($str)
{
    $ret = array();
    $len = strlen($str);
    $count = 0;
    for($i = 0; $i <= $len; $i ++)
    {
        $char = @$str[$i] ?: null;
        if($char == '~')
        {
            $count ++;
        }
        elseif($count > 0)
        {
            // Found end of sequence
            $ret[] = array(
                'start' => $i - $count,
                'end' => $i - 1,
                'len' => $count
            );
            $count = 0;
        }
    }
    return $ret;
}

示例用法:

print_r(findSequences('~ABC~~~123~~'));

将输出一个数组,其中包含找到的匹配项的详细信息:

Array
(
    [0] => Array
        (
            [start] => 0
            [end] => 0
            [len] => 1
        )
    [1] => Array
        (
            [start] => 4
            [end] => 6
            [len] => 3
        )
    [2] => Array
        (
            [start] => 10
            [end] => 11
            [len] => 2
        )
)

感谢大家的回答
他们鼓励我更加努力地寻找一个简单的解决方案。

我想到了这个:-

$lasttilde=$firsttilde;
while ($filedata[$lasttilde]=='~') { $lasttilde++; }

那么$filedata的特定部分中的波浪号的数量就是$lasttilde$firsttilde之间的差值