Как упорядочить по сегменту результаты preg_match_all?

Я использую PHP для создания списка ссылок на текст, выполняя поиск preg_match_all в таблице базы данных. Вот PHP-код:

$query = "SELECT primary_tag,display_short_title,content FROM topics;";
$result = mysql_query($query) or die("Query failed : " . mysql_error());
$num_results = mysql_num_rows($result);
for ($i = 0; $i < $num_results; $i++) {
  $row = mysql_fetch_array($result);
  if (preg_match_all("/(\<i\>U\<\/i\>|U) [0-9]{1,2}\.[0-9]{1,7}/", $row["content"], $matches)) {
    foreach ($matches[0] as $match) {
    $match = ltrim(strip_tags($match), "U ");
    echo '<p class="textmark_result">' . $match;
    echo '  <a href="../Essays/topic.php?shorttitle=' . $row["primary_tag"] . '">' . $row["display_short_title"] . '</a>';
    echo "</p>\n";
    }
  }
}

А результаты (просмотр исходника) выглядят так:

<p class="textmark_result">15.1737  <a href="../Essays/topic.php?shorttitle=medicine">Medicine</a></p>
<p class="textmark_result">5.678  <a href="../Essays/topic.php?shorttitle=science">Science</a></p>
<p class="textmark_result">14.665  <a href="../Essays/topic.php?shorttitle=science">Science</a></p>

На получившейся веб-странице я хочу упорядочить результаты по десятичному знаку в середине, $match в коде, чтобы (в этом примере) сначала было 5,678, затем 14,665, затем 15,1737. Есть ли способ сделать это?

Благодарю вас!


person user2193632    schedule 09.05.2013    source источник


Ответы (1)


Три шага:

  1. Получите все ваши совпадения и добавьте их в массив - floatval($match) является ключом.
  2. Отсортируйте полученный массив по ключу (поплавки сортируются по числовому значению, строки сортируются по символам — следовательно, floatval(...)).
  3. Итерация по отсортированному массиву

Код:

// MySQL stuff goes here ...
// create empty array
$results = array();
for ($i = 0; $i < $num_results; $i++) {
    $row = mysql_fetch_array($result);
    if (preg_match_all("/(\<i\>U\<\/i\>|U) [0-9]{1,2}\.[0-9]{1,7}/", $row["content"], $matches)) {
        foreach ($matches[0] as $match) {
            $match = ltrim(strip_tags($match), "U ");
            // array pseudo key is the float value of $match
            // add '_key' member for usort()
            $row['_key'] = floatval($match);
            $results[] = $row;
        }
    }
}
// sort the array by the float key
usort($results, function($a, $b) {
    if($a['_key'] == $b['_key']) return 0;
    elseif($a['_key'] > $b['_key']) return 1;
    else return -1;
});

// ... then display stuff in order
foreach($results as $row) {
    echo '<p class="textmark_result">' . (string)$row['_key'];
    echo '  <a href="../Essays/topic.php?shorttitle=' 
    . $row["primary_tag"] . '">' . $row["display_short_title"] . '</a>';
    echo "</p>\n";
}
person Lukas    schedule 09.05.2013
comment
Спасибо за понимание floatval; Я согласен, это имеет решающее значение для проблемы, и я не знал об этом. Когда я запускаю предложенный вами код, он сокращает десятичные числа до целых и не переупорядочивает их. Он выдает '‹p class=textmark_result›15 ‹a href=../Essays/topic.php?shorttitle=medicine›Medicine‹/a›‹/p› ‹p class=textmark_result›5 ‹a href=../ Эссе/topic.php?shorttitle=science›Наука‹/a›‹/p› ‹p class=textmark_result›14 ‹a href=../Essays/topic.php?shorttitle=science›Наука‹/a›‹/ p>' Сейчас я начинаю смотреть на это, чтобы понять, почему это происходит. - person user2193632; 09.05.2013
comment
Я только что просмотрел это и заметил, что PHP не поддерживает индексы с плавающей запятой. Я заменил ksort() на usort(). Теперь он сортирует массив по псевдоключу, хранящемуся в значении массива. - person Lukas; 09.05.2013
comment
Большое спасибо, что проверили это. Ваш обновленный код восстанавливает десятичные значения, но результаты по-прежнему не сортируются. '‹p class=textmark_result›15.1737 ‹a href=../Essays/topic.php?shorttitle=medicine›Medicine‹/a›‹/p› ‹p class=textmark_result›5,678 ‹a href=../Essays/ topic.php?shorttitle=science›Наука‹/a›‹/p› ‹p class=textmark_result›14.665 ‹a href=../Essays/topic.php?shorttitle=science›Наука‹/a›‹/p› — Я тоже проверяю сортировку. - person user2193632; 09.05.2013
comment
Ах да... конечно. Я написал функцию сортировки в тестовом сценарии и забыл ее изменить. Изменен вызов usort на usort($results, function($a, $b) { ... }); - person Lukas; 09.05.2013
comment
Хм. Я понимаю, что вы имеете в виду, но новый вызов usort дает тот же результат — все идеально, кроме сортировки. Что бы это ни стоило (и я новичок, так что это может быть не по делу), я попытался взорвать и повторить массив $results непосредственно перед вызовом usort, чтобы увидеть, что он пытается отсортировать, и ничего не происходит. Возможно, массив не создается? Я просто вставлял '$results_ex = взорвать (, , $results); эхо $results_ex;'. - person user2193632; 09.05.2013
comment
Что ж, попробуй var_dump($results) вместо explode(). Элементы массива сами являются массивами. Когда они преобразуются в строки (что и делает explode()), вы не получите от них многого. Тем не менее, я попробовал этот код с некоторыми фиктивными данными и var_dump($results)ed до и после usort(...), и у меня он отлично работает. - person Lukas; 09.05.2013
comment
А... понял. Сортировка и эхо должны выполняться вне цикла for, иначе совпадения будут сортироваться только для выбранной строки. Сделал очередное обновление. - person Lukas; 09.05.2013