Для заданной строки, например:
$string = " this is a string ";
Каков наилучший подход для возврата массива CSV, содержащего одно число для каждого слова, которое представляет его первую позицию символов следующим образом:
$string = " this is a string ";
^ ^ ^ ^
2 11 16 20
В идеале выводом будет просто массив:
2,11,16,20
Пока что вот что у меня есть, но я думаю, что это немного над моей головой, учитывая мои ограниченные навыки:
$string = " this is a string ";
$string = rtrim($string); //just trim the right sides spaces
$len = strlen($string);
$is_prev_white = true;
$result = "";
for( $i = 0; $i <= $len; $i++ ) {
$char = substr( $string,$i,1);
if(!preg_match("/\s/", $char) AND $prev_white){
$result .= $i.",";
$prev_white = false;
}else{
$prev_white = true;
}
}
echo $result;
Я получаю:
2,4,11,16,20,22,24,26
Просто, но прогрессирующий 🙂 решение с preg_match_all
а также array_walk
функции:
использование preg_match_all
функция с PREG_OFFSET_CAPTURE
флаг:
PREG_OFFSET_CAPTURE : Если этот флаг пропущен, для каждого совпадения будет также возвращено смещение вспомогательной строки. Обратите внимание, что это меняет значение Матчи в массив, где каждый элемент является массивом, состоящим из совпадающей строки со смещением 0 и его смещения строки в предмет по смещению 1.
$string = " this is a string "; // subject
preg_match_all("/\b\w+\b/iu", $string, $matches, PREG_OFFSET_CAPTURE);
array_walk($matches[0], function(&$v){ // filter string offsets
$v = $v[1];
});
var_dump($matches[0]);
// the output:
array (size=4)
0 => int 2
1 => int 11
2 => int 16
3 => int 20
Вы хотите флаг PREG_OFFSET_CAPTURE:
$string = " this is a string ";
preg_match_all('/(?:^|\s)([^\s])/', $string, $matches, PREG_OFFSET_CAPTURE);
$result = $matches[1];
echo var_dump($result);
Регулярное выражение:
(?:^|\s) // Matches white space or the start of the string (non capturing group)
(^\s) // Matches anything *but* white space (capturing group)
Передача PREG_OFFSET_CAPTURE приводит к тому, что preg_match () или preg_match_all () возвращают совпадения в виде двухэлементных массивов, которые содержат как совпадающую строку, так и индекс этого совпадения внутри искомой строки. Результат приведенного выше кода:
array(4) {
[0]=> array(2) { [0]=> string(1) "t" [1]=> int(2) }
[1]=> array(2) { [0]=> string(1) "i" [1]=> int(11) }
[2]=> array(2) { [0]=> string(1) "a" [1]=> int(16) }
[3]=> array(2) { [0]=> string(1) "s" [1]=> int(20) }
}
Таким образом, вы можете получить массив только индексов с
$firstChars = array_column($result, 1);
Сопоставление с регулярным выражением Php предоставляет флаг для возврата смещений вместо сопоставленных подстрок. Используйте следующий фрагмент:
$hits = [];
preg_match_all("/(?<=\s)\w/", " this is a string ", $hits, PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE);
$result = array_column ( $hits[0], 1 );
$s_result = join ( ", ", $result);
echo $s_result;
Шаблон регулярного выражения использует положительный взгляд назад, чтобы найти первый символ после пробела. Призыв к array_column
извлечь данные результата из многомерного массива, возвращенного как описание соответствия шаблона. join
объединяет элементы массива в строку, выбранный разделитель превращает его в строку CSV.
Для получения более подробной информации обратитесь к документации php для array_column а также preg_match_all.
Живой пример Вот. Согласно этому сайту, решение работает с php 5.5.0.
Шаблон, который вы ищете, достаточно прост, чтобы регулярное выражение не было необходимо, чтобы соответствовать ему. Вы можете сделать это, просто зацикливая строку.
$l = strlen($string);
$result = array();
// use this flag to keep track of whether the previous character was NOT a space
$c = false;
for ($i=0; $i < $l; $i++) {
// if the previous character was a space and the current one isn't...
if (!$c && $string[$i] != ' ') {
// add current index to result
$result[] = $i;
}
// set the 'not a space' flag for the current character
$c = $string[$i] != ' ';
}
Давайте попробуем это без регулярных выражений. Я надеюсь, что это работа для вас.
$str=" w this is a string ";
echo "<pre>";
print_r(first_letter_index($str));
function first_letter_index($str)
{
$arr2 = array_map('trim',str_split($str));
$result=array();
foreach($arr2 as $k=>$v)
{
if(!empty($v) && empty($arr2[$k-1]))
{
$result[$k]=$v;
}
}
return $result;
}
Также вы можете использовать preg_split
с двумя флагами.
$string = " this is a string ";
$flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE;
// \W+ matches one or more non word characters
$csv = implode(",", array_column(preg_split('/\W+/', $string, -1, $flags), 1));
echo $ csv;
2,11,16,20
Если вам нужны слова со смещением, просто удалите array_column
а также implode
часть.
$ res = preg_split ('/ \ W + /', $ string, -1, $ flags);