我正在使用php将文本服务器端合并到rtf格式的文件中。我的字段由文件不同部分的波浪号序列标识。每个序列都有不同的长度。为了使用substr_replace
将字段替换为合并材质,我需要计算波浪号序列的长度。我可以找到第一个波浪号没有问题使用:
$firsttilde=strpos($filedata,'~',$currentposinfile);
其中(在此代码中)$filedata
是包含文件内容的字符串,$currentposinfile
是我搜索的起点。我的问题是,我找不到一个函数可以计算序列中相同字符的数量。
从$filedata
的第一个波浪号开始,我看到的部分看起来是这样的(换句话说,波浪号序列):
"~~~~~~"
我已经尝试过strrpos
来查找最后一个波浪号,但这是在$filedata
的后面部分中查找包含波浪号的字段。我所想做的就是从字符串中我所知道的位置开始计算波浪号的数量,但我找不到任何函数来做这件事。不过肯定有一个。
您可以将preg_match_all
与PREG_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
之间的差值