regex — PHP получает позицию каждого первого символа в строке в массив

Для заданной строки, например:

$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

6

Решение

Просто, но прогрессирующий 🙂 решение с 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

http://php.net/manual/en/function.preg-match-all.php

http://php.net/manual/en/function.array-walk.php

1

Другие решения

Вы хотите флаг 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);
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.

1

Шаблон, который вы ищете, достаточно прост, чтобы регулярное выражение не было необходимо, чтобы соответствовать ему. Вы можете сделать это, просто зацикливая строку.

$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] != ' ';
}
0

Давайте попробуем это без регулярных выражений. Я надеюсь, что это работа для вас.

$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;
}
0

Также вы можете использовать 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);

0
По вопросам рекламы [email protected]