背景
我有一个数组,我是通过使用0d0a
基于preg_split('/(?<=0d0a)(?!$)/')
的每次出现来分割字符串来创建的。
例如:
$string = "78781110d0a78782220d0a";
将分为:
Array ( [0] => 78781110d0a [1] => 78782220d0a )
有效的数组元素必须以7878
开头,以0d0a
结尾。
问题
但有时候,字符串中会有一个额外的0d0a
,它会分成一个额外的无效数组元素,即不以7878
开头。
以此字符串为例:
$string = "78781110d0a2220d0a78783330d0a";
这分为:
Array ( [0] => 78781110d0a [1] => 2220d0a [2] => 78783330d0a )
但实际上应该是:
Array ( [0] => 78781110d0a2220d0a [1] => 78783330d0a)
我的解决方案
我编写了以下(杂乱)代码来解决这个问题:
$data = Array('78781110d0a','2220d0a','78783330d0a');
$i = 0; //count for $data array;
$j = 0; //count for $dataFixed array;
$dataFixed = $data;
foreach($data as $packet) {
if (substr($packet,0,4) != "7878") { //if packet doesn't start with 7878, do some fixing
if ($i != 0) { //its the first packet, can't help it!
$j++;
if ((substr(strtolower($packet), -4, 4) == "0d0a")) { //if the packet doesn't end with 0d0a, its 'mostly' not valid, so discard it
$dataFixed[$i-$j] = $dataFixed[$i-$j] . $packet;
}
unset($dataFixed[$i-$j+1]);
$dataFixed = array_values($dataFixed);
}
}
$i++;
}
描述
我首先将数组复制到另一个数组$dataFixed
。在foreach
数组的$data
循环中,我会检查它是否以7878
开头。如果没有,我将其加入$data
中的前一个数组。然后我取消设置$dataFixed
中的当前数组并使用array_values
重置数组元素。
但我对这个解决方案并不是很有信心。有更好,更有效的方法吗?
更新
如果输入字符串不像它应该的那样以0d0a
结尾怎么办?它将坚持前一个数组元素..
例如:在字符串78781110d0a2220d0a78783330d0a0000
中,0000
应该被分隔为另一个数组元素。
答案 0 :(得分:3)
使用其他positive lookahead (?=7878)
来形成:
preg_split('/(?<=0d0a)(?=7878)/',$string)
注意:我删除了(?!$)
,因为根据您的示例数据,我不确定这是什么。
例如,此代码:
$string = "78781110d0a2220d0a78783330d0a";
$array = preg_split('/(?<=0d0a)(?=7878)(?!$)/',$string);
print_r($array);
结果:
Array ( [0] => 78781110d0a2220d0a [1] => 78783330d0a )
<强>更新强>
根据您在输入字符串末尾添加可能的随机字符的修订问题,您可以添加三行来制作完整的程序:
$string = "78781110d0a2220d0a787830d0a330d0a0000";
$array = preg_split('/(?<=0d0a)(?=7878)/',$string);
$temp = preg_split('/(7878.*0d0a)/',$array[count($array)-1],null,PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);
$array[count($array)-1] = $temp[0];
if(count($temp)>1) { $array[] = $temp[1]; }
print_r($array);
我们基本上进行初始拆分,然后按照预期的数据格式拆分结果数组的最后一个元素,使用PREG_SPLIT_DELIM_CAPTURE
保留分隔符。 PREG_SPLIT_NO_EMPTY
确保如果输入字符串不以随机字符结尾,我们将不会获得空数组元素。
更新2:
根据您在下面的评论,您似乎暗示任何所需匹配项之间可能存在随机字符,并且您希望保留这些随机字符,您可以这样做:
$string = "0078781110d0a2220d0a2220d0a0000787830d0a330d0a000078781110d0a2220d0a0000787830d0a330d0a0000";
$split1 = preg_split('/(7878.*?0d0a)/',$string,null,PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);
$result = array();
foreach($split1 as $e){
$split2 = preg_split('/(.*0d0a)/',$e,null,PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);
foreach($split2 as $el){
// test if $el doesn't start with 7878 and ends with 0d0a
if(strpos($el,'7878') !== 0 && substr($el,-4) == '0d0a'){
//if(preg_match('/^(?!7878).*0d0a$/',$el) === 1){
$result[ count($result)-1 ] = $result[ count($result)-1 ] . $el;
} else {
$result[] = $el;
}
}
}
print_r($result);
此处采用的策略与上述不同。首先,我们使用nongreedy正则表达式.*?
,根据与所需数据匹配的分隔符拆分输入字符串。此时我们有一些字符串包含所需值的结尾和最后的一些垃圾,所以我们再次根据最后一次出现的“0d0a”和贪婪的正则表达式.*0d0a
进行拆分。然后我们将任何不以“7878”开头但以“0d0a”结尾的结果值附加到前一个值,因为它应该修复分裂的第一和第二半,因为它包含一个额外的“0d0a”。 / p>
我为最里面的if
语句提供了两种方法,一种使用正则表达式。在我的测试中,正则表达式稍微慢一点,所以我留下了一个注释掉的。
我可能仍然没有满足您的全部要求,因此您必须告诉我它是否有效并且可能提供完整的数据集。
答案 1 :(得分:1)
为什么不使用preg_match_all?您可以避免所有非捕获组(向前看,向后看)以分割字符串(没有非捕获组删除匹配),只需找到您要查找的匹配项:
<?php
$string = "00787817878110d0a22278780d0a78783330d0a00";
preg_match_all('/7878.*?0d0a(?=7878|[^(7878)]*?$)/', $string, $arr);
print_r($arr);
?>
提供数组$arr[0] => ( [0] => 787817878110d0a22278780d0a, [1] => 78783330d0a )
。剥离前导和尾随垃圾字符(无论是以7878
开头还是以7878
或0d0a
结尾。
所以$ arr [0]将是您正在寻找的值数组。
请参阅ideone
上的示例使用多个7878
值和多个0d0a
值(即使这很荒谬)。
如果拆分更符合您的风格,为什么不完全避免使用正则表达式?
<?php
$string = "787817878110d0a22278780d0a78783330d0a";
$arr = explode('0d0a7878', $string);
$string = implode('0d0a,7878', $arr);
$arr = explode(',', $string);
print_r($arr);
?>
这里我们用分隔符0d0a7878
分割字符串,这是@ CharlieGorichanaz的解决方案正在做的事情,并为他提供快速,准确的解决方案。然后我们添加一个逗号,因为谁不喜欢逗号分隔的值?我们再次在逗号上explode获取所需值的数组。在性能方面,这应该比使用正则表达式更快。请参阅example。
答案 2 :(得分:1)
我认为您使用的分隔符“0d0a”也恰好是内容的一部分!只要分隔符也可以成为内容的一部分,就不可能避免获取垃圾数据。不知何故,分隔符必须是唯一的。
可能的解决方案。
答案中给出的解决方案仅考虑您共享的样本数据。如果你想知道字符串的内容是什么,那么其他人给出的这些解决方案非常好用。否则这些解决方案无法保证您的保证!
最佳解决方案:修复右分隔符,然后使用正则表达式或爆炸您喜欢的任何内容。