Commit 4c45b8a9 authored by generalredneck's avatar generalredneck

Issue #2790345: Negative Decimal Numbers sort Incorrectly

parent 51879a6c
<?php
/**
* @STUBBED
* @file
* The Views Natural Sort module include file.
*/
/**
* Remove all the configured words from the beginning of the string only.
*
* @param string $string
* The string we wish to transform.
*
* @return string
* The transformed string.
*/
function views_natural_sort_remove_beginning_words($string) {
$beginning_words = [
......@@ -10,9 +21,8 @@ function views_natural_sort_remove_beginning_words($string) {
t('An'),
t('La'),
t('Le'),
t('Il')
t('Il'),
];
if (empty($beginning_words)) {
return $string;
}
......@@ -25,6 +35,15 @@ function views_natural_sort_remove_beginning_words($string) {
);
}
/**
* Remove all the configured words from the string.
*
* @param string $string
* The string we wish to transform.
*
* @return string
* The transformed string.
*/
function views_natural_sort_remove_words($string) {
$words = [
t('and'),
......@@ -43,12 +62,21 @@ function views_natural_sort_remove_words($string) {
),
array(
' ',
''
'',
),
$string
);
}
/**
* Remove all the configured symbols from the string.
*
* @param string $string
* The string we wish to transform.
*
* @return string
* The transformed string.
*/
function views_natural_sort_remove_symbols($string) {
$symbols = "#\"'\\()[]";
if (strlen($symbols) == 0) {
......@@ -74,13 +102,16 @@ function views_natural_sort_remove_symbols($string) {
* - Thousands separates are ignored, using the comma as the thous. character
* - Numbers may be up to 99 digits before the decimal, up to the precision
* of the processor.
*
* @param string $string
* The string we wish to transform.
*/
function views_natural_sort_numbers($string) {
// Find an optional leading dash (either preceded by whitespace or the first
// character) followed by either:
// - an optional series of digits (with optional embedded commas), then a
// period, then an optional series of digits
// - a series of digits (with optional embedded commas)
// - an optional series of digits (with optional embedded commas), then a
// period, then an optional series of digits
// - a series of digits (with optional embedded commas)
return preg_replace_callback(
'/(\s-|^-)?(?:(\d[\d,]*)?\.(\d+)|(\d[\d,]*))/',
'_views_natural_sort_number_transform_match_callback',
......@@ -89,36 +120,48 @@ function views_natural_sort_numbers($string) {
}
/**
* Encodes a string representing numbers into a special format that can be sorted alphanumerically.
* Transforms a string representing numbers into a special format.
*
* This special format can be sorted as if it was a number but in reality is
* being sorted alphanumerically.
*
* @param array $match
* array of matches passed from preg_replace_callback
* Array of matches passed from preg_replace_callback
* $match[0] is the entire matching string
* $match[1] if present, is the optional dash, preceded by optional whitespace
* $match[2] if present, is whole number portion of the decimal number
* $match[3] if present, is the fractional portion of the decimal number
* $match[4] if present, is the integer (when no fraction is matched)
* $match[4] if present, is the integer (when no fraction is matched).
*
* @return string
* String representing a numerical value that will sort numerically in an
* alphanumeric search.
*/
function _views_natural_sort_number_transform_match_callback($match) {
function _views_natural_sort_number_transform_match_callback(array $match) {
// Remove commas and leading zeros from whole number
$whole = (string)(int)str_replace(',', '', (isset($match[4]) && strlen($match[4]) > 0) ? $match[4] : $match[2]);
// Remove trailing 0's from fraction, then add the decimal and one trailing 0
$fraction = trim('.' . $match[3], '0') . '0';
// Remove commas and leading zeros from whole number.
$whole = (string) (int) str_replace(',', '', (isset($match[4]) && strlen($match[4]) > 0) ? $match[4] : $match[2]);
// Remove traililng 0's from fraction, then add the decimal and one trailing
// 0 and a space. The space serves as a way to always sort shorter decimal
// numbers that match exactly as less than longer ones.
// Ex: 3.05 and 3.05011.
$fraction = trim('.' . $match[3], '0') . '0 ';
$encode = sprintf('%02u', strlen($whole)) . $whole . $fraction;
if (strlen($match[1])) {
// Negative number. Make 10's complement. Put back any leading white space and the dash
// Requires intermediate to avoid double-replacing the same digit. str_replace seems to
// work by copying the source to the result, then successively replacing within it,
// rather than replacing from the source to the result.
$digits = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
$intermediate = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j');
$rev_digits = array('9', '8', '7', '6', '5', '4', '3', '2', '1', '0');
$encode = $match[1] . str_replace($intermediate, $rev_digits, str_replace($digits, $intermediate, $encode));
// Negative number. Make 10's complement. Put back any leading white space
// and the dash requires intermediate to avoid double-replacing the same
// digit. str_replace() seems to work by copying the source to the result,
// then successively replacing within it, rather than replacing from the
// source to the result.
// In this case since rules are reverced we also have to use a character
// that would be sorted higher than a space when a number is being compared
// against a longer one that is identical in negative numbers. This is so
// that longer numbers are always LESS than sorter numbers that have
// identical beginnings. Ex: -3.05 and -3.05011.
$digits = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' ');
$intermediate = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k');
$rev_digits = array('9', '8', '7', '6', '5', '4', '3', '2', '1', '0', ':');
$encode = $match[1] . str_replace($intermediate, $rev_digits, str_replace($digits, $intermediate, $encode));
}
return $encode;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment