Javascript: порядковый суффикс для чисел с определенным классом CSS

Я пытаюсь отобразить числа в определенной таблице с порядковыми суффиксами. В таблице всегда отображаются три числа, взятые из XML-файла. Цифры показывают ранги, например, это может быть 6-й, 120-й, 131-й. На выходе получается таблица, которая будет выглядеть так:

<table>
    <tr>
        <td class='ordinal'>6</td>
        <td class='ordinal'>120</td>
        <td class='ordinal'>131</td>
    </tr>
</table>

В идеале я хотел бы использовать javascript, и я нашел несколько очень хороших решений в stackoverflow, например этот. Однако я изо всех сил пытаюсь применить эту функцию ко всем числам в таблице, а не вводить каждое число по отдельности. Я попытался использовать класс CSS, чтобы моя функция выглядела так:

<script type="text/javascript">
$(function(){
    $(".ordinal").each(function(){
        var j = i % 10;
        if (j == 1 && i != 11) {
            return i + "st";
        }
        if (j == 2 && i != 12) {
            return i + "nd";
        }
        if (j == 3 && i != 13) {
            return i + "rd";
        }
        return i + "th";
        });
})
</script>

но это не работает, возможно, потому что я где-то напортачил с кодом. Может быть, кто-нибудь здесь может помочь мне и сказать мне, где я ошибся?

Большое спасибо за Вашу помощь!


person rf2012    schedule 04.04.2013    source источник


Ответы (8)


Мое собственное предложение:

$(".ordinal").text(function (i, t) {
    i++;
    var str = i.toString().slice(-1),
        ord = '';
    switch (str) {
        case '1':
            ord = 'st';
            break;
        case '2':
            ord = 'nd';
            break;
        case '3':
            ord = 'rd';
            break;
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
        case '0':
            ord = 'th';
            break;
    }
    return i + ord;
});

демонстрация JS Fiddle.

Это эффективно берет увеличенное число (i++, чтобы начать с 1, а не 0), преобразует его в строку, а затем просматривает последнее число этой строки. Это должно работать для любого числа, поскольку порядковый номер основан исключительно на этом последнем числе.

Вы также можете расширить прототип Number для реализации этой функциональности:

Number.prototype.ordinate = function(){
    var num = this + 1,
        last = num.toString().slice(-1),
        ord = '';
    switch (last) {
        case '1':
            ord = 'st';
            break;
        case '2':
            ord = 'nd';
            break;
        case '3':
            ord = 'rd';
            break;
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
        case '0':
            ord = 'th';
            break;
    }
    return num.toString() + ord;
};

$(".ordinal").text(function (i, t) {
    return i.ordinate();
});

демонстрация JS Fiddle.

Отредактировано, чтобы предложить небольшую альтернативу:

Number.prototype.ordinate = function(){
    var num = this,
        last = num.toString().slice(-1),
        ord = '';
    switch (last) {
        case '1':
            ord = 'st';
            break;
        case '2':
            ord = 'nd';
            break;
        case '3':
            ord = 'rd';
            break;
        default:
            ord = 'th';
            break;
    }
    return num.toString() + ord;
};

$(".ordinal").text(function (i,t) {
    return t.replace(/(\d+)/g, function(a){
        return parseInt(a, 10).ordinate();
    });
});

демонстрация JS Fiddle.

По сути, это перебирает каждый элемент .ordinal, заменяя присутствующие числа (теми же) числами с добавленным к нему порядковым суффиксом.


Отредактировано для решения проблемы, поднятой в комментариях ниже, что 11, 12 и 13 получали порядковый суффикс st, nd и rd (соответственно). Теперь это исправлено на th во всех случаях:

Number.prototype.ordinate = function(){
    var num = this,
        numStr = num.toString(),
        last = numStr.slice(-1),
        len = numStr.length,
        ord = '';
    switch (last) {
        case '1':
            ord = numStr.slice(-2) === '11' ? 'th' : 'st';
            break;
        case '2':
            ord = numStr.slice(-2) === '12' ? 'th' : 'nd';
            break;
        case '3':
            ord = numStr.slice(-2) === '13' ? 'th' : 'rd';
            break;
        default:
            ord = 'th';
            break;
    }
    return num.toString() + ord;
};

демонстрация JS Fiddle.

Рекомендации:

person David says reinstate Monica    schedule 04.04.2013
comment
Это выглядит интересно, спасибо, Дэвид, но, похоже, 1-й, 2-й, 3-й и т. д. не прикрепляются к 1-му ряду, 2-му ряду, 3-му ряду и т. д. Я бы хотел, чтобы st, nd, rd присоединялись к номеру в ячейке таблицы. Я не мог заставить это работать, есть ли способ сделать это? - person rf2012; 04.04.2013
comment
Да, именно это и происходит у меня под Chrome 25/Win XP. Какой браузер/платформу вы используете, которая не работает? (Я не могу протестировать IE, так как IE‹8 не работает с JS Fiddle в целом.) - person David says reinstate Monica; 04.04.2013
comment
О боже, я перечитал свой комментарий, и это довольно запутанно, прошу прощения. Предложение должно было означать, что оно, кажется, прикреплено... Дело, однако, в том, что я не хочу, чтобы ячейки таблицы нумеровались последовательно, а просто число внутри ячейки отображалось как порядковый номер. Это имеет больше смысла? Прошу прощения за мой предыдущий неясный комментарий. Я тестировал его на Chrome 26/Win 7. - person rf2012; 04.04.2013
comment
Круто, отлично работает!!! Теперь есть только последняя крошечная проблема. Есть ли способ отображать 11-13 (и 111-113, и так далее) как 11-й, 12-й и 13-й, а не 11-й, 12-й, 13-й, как сейчас. Я устал добавлять case '13', но это не помогло. Большое спасибо за вашу помощь! - person rf2012; 04.04.2013
comment
Хорошо, я думаю, теперь это исправлено? - person David says reinstate Monica; 05.04.2013
comment
ДА, я думаю тоже так :-) Большое спасибо, Дэвид!!! Я очень ценю вашу помощь и терпение! - person rf2012; 05.04.2013
comment
Пожалуйста, рад был быть полезным! И я несколько встревожен тем, что мне не пришло в голову по-разному относиться к числам, оканчивающимся на 11, 12 и 13, когда я писал ответ. - person David says reinstate Monica; 05.04.2013
comment
в вашем последнем примере вы нигде не используете переменную len - person vsync; 27.11.2014

function nth(n){
    if(isNaN(n) || n%1) return n;   
    var s= n%100;
    if(s>3 && s<21) return n+'th';
    switch(s%10){
        case 1: return n+'st';
        case 2: return n+'nd';
        case 3: return n+'rd';
        default: return n+'th';
    }
}

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

person kennebec    schedule 04.04.2013

Я создал два подхода: один с использованием Prototype, другой как плагин:

Number.prototype.between = function(n,m){ return this > n && this < m }
Number.prototype.ORDINATE_INDEX = ["th","st","nd","rd"];
Number.prototype.toOrdinate = function(){
    var
        nthMod = (this % 10),
        index =  nthMod > 3 || this.between(10,20) ? 0 : nthMod
    ;

    return this + this.ORDINATE_INDEX[index];
};

$(".ordinal").text(function (index, element) {
    return parseInt(element).toOrdinate();
});

Это один из плагинов Jquery:

(function($){
    var numberTool = new (function(){
        var private = {};

        private.ORDINATE_INDEX = ["th","st","nd","rd"];

        private.parseOrdinary = function(number)
        {
            var
                nthMod = (number % 10),
                index =  nthMod > 3 || private.between(number, 10,20) ? 0 : nthMod
            ;

            return number + private.ORDINATE_INDEX[index];
        }

        private.between = function(number, n,m){
            return number > n && number < m
        }

        this.isNumeric = function(number)
        {
            return !isNaN(parseFloat(number)) && isFinite(number);
        }

        this.toOrdinary = function(number)
        {
            return this.isNumeric(number) ? private.parseOrdinary(number) : number;
        }
    });


    $.fn.toOrdinary = function(){
        return this.each(function(){
            $element = $(this);
            $element.text(numberTool.toOrdinary($element.text()));
        }); 
    };
})(jQuery);

$(".ordinal").toOrdinary();
$(".ordinal").toOrdinary();
$(".ordinal").toOrdinary();

Проверено на JSFIDDLE:

Пример версии прототипа: http://jsfiddle.net/f8vQr/6/

Пример версии JQuery: http://jsfiddle.net/wCdKX/27/

person lac_dev    schedule 14.07.2013

Это не работает, потому что вы возвращаете строки в $.each, фактически не используя их. Использование будет зависеть от вашего HTML, но вот пример установки текста .ordinal в значение.

Вам также не хватало параметра i в обработчике событий, и вы можете увеличить i, чтобы начать с 1st вместо 0th.

jsFiddle

$(".ordinal").each(function (i) {
    i++;
    var j = i % 10,
        str;
    if (j == 1 && i != 11) {
        str = i + "st";
    } else if (j == 2 && i != 12) {
        str = i + "nd";
    } else if (j == 3 && i != 13) {
        str = i + "rd";
    } else {
        str = i + "th";
    }
    $(this).text(str);
});

Если у вас уже есть числа в ваших элементах, лучше не полагаться на индекс и вместо этого проверять число, а затем добавлять строку в конец.

jsFiddle

$(document).ready(function () {
    $(".ordinal").each(function (i) {
        var j = parseInt($('ordinal').text(), 10) % 10,
            str;
        if (j == 1 && i != 11) {
            str = "st";
        } else if (j == 2 && i != 12) {
            str = "nd";
        } else if (j == 3 && i != 13) {
            str = "rd";
        } else {
            str = "th";
        }
        var elem = $(this)
        elem.text(elem.text() + str);
    });
});
person Daniel Imms    schedule 04.04.2013
comment
Круто, спасибо, сработало! Однако теперь у меня проблема, что каждое число, например 132, возвращается как 17-е, а не 132-е. Мои цифры превышают 200. Вы знаете, в чем может быть причина этой ошибки? - person rf2012; 04.04.2013
comment
У меня отлично работает jsfiddle.net/Tyriar/gWnUJ. Вы что-то пропустили в коде? - person Daniel Imms; 04.04.2013
comment
Ах, я задал вопрос до того, как увидел i++, извините. Однако нет, он возвращает числа как просто 1-й, 2-й, 3-й, а не как, скажем, 17-й, 132-й, 146-й. Я ввожу числа через документ XML, если это имеет значение!? Таким образом, код будет выглядеть так: <table> <tr><td class='ordinal'>4</td></tr> </table> и должен возвращать 4-й... - person rf2012; 04.04.2013
comment
Обновлено более подходящим решением для элементов, содержащих число. - person Daniel Imms; 04.04.2013
comment
Потрясающе, спасибо!!! Я как раз обновлял свой первоначальный вопрос. Теперь единственная проблема заключается в том, что 1 возвращается как 1-й. Можно ли сохранить окончания «st», «nd» и «rd» для всех чисел, оканчивающихся на 1,2 или 3, кроме 11,12,13? - person rf2012; 04.04.2013

Порядковый суффикс в одной строке

var integerWithSuffix=originalInteger+(['st','nd','rd'][( originalInteger +'').match(/1?\d\b/)-1]||'th');

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

http://jsfiddle.net/thisishardcoded/DbSMB/

person Jim    schedule 01.05.2013
comment
Можете ли вы немного больше объяснить RegExp или дать ссылку на источник, где вы это нашли?! - person yckart; 16.08.2013
comment
Регулярное выражение выберет либо одну цифру, если задана одна цифра, либо последнюю цифру в наборе цифр, 1 будет выглядеть как 1, а 123 будет выглядеть как 3, чтобы определить суффикс. Может начало 1? не требуется, так как \d\b поймает одну цифру или последнюю цифру в наборе цифр. - person Danny; 17.11.2014

Я бы сделал что-то вроде этого, основываясь на ответе Дэвида Томаса:

Number.prototype.ordinate = function(){
    var num = this,
        ones = num % 10, //gets the last digit
        tens = num % 100, //gets the last two digits
        ord = ["st","nd","rd"][ tens > 10 && tens < 20 ? null : ones-1 ] || 'th';
    return num.toString() + ord;
};

Он выполняет то же самое. Если последние 2 цифры числа находятся в диапазоне от 11 до 19 ИЛИ последняя цифра находится в диапазоне от 4 до 0, по умолчанию используется значение «th», в противном случае из массива будут извлечены «st», «nd» или «rd». на своих местах.

Мне очень нравится идея создания функции-прототипа, но я бы определенно оставил приращение индекса вне функции-прототипа, чтобы сделать ее более универсальной:

$(".ordinal").text(function (i, t) {
    return (++i).ordinate();
});

демонстрация JS Fiddle

person CSharp    schedule 30.05.2013

function ordsfx(a){return["th","st","nd","rd"][(a=~~(a<0?-a:a)%100)>10&&a<14||(a%=10)>3?0:a]}

См. аннотированную версию по адресу https://gist.github.com/furf/986113#file-annotated-js

Короткий, приятный и эффективный, как и должны быть служебные функции. Работает с любым целым числом со знаком/без знака/числом с плавающей запятой. (Хотя я не могу представить себе необходимость упорядочения поплавков)

person hndcrftd    schedule 27.09.2013

Это то, что я использую, и оно работает для любого года, месяца, дня (високосного года):

// panelyear, panelmonth and panelday are passed as parameters

var PY01 = parseInt(panelyear); var PM01 = (parseInt(panelmonth) - 1); PD01 = parseInt(panelday);

var now = new Date(PY01, PM01, PD01);
var start = new Date(PY01, 0, 0);
var diff = (now - start) + ((start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000);
var oneDay = 1000 * 60 * 60 * 24;
var day = Math.floor(diff / oneDay);

function getNumberWithOrdinal(n) { var s = ["th","st","nd","rd"], v = n % 100; return n + (s[(v - 20) % 10] || s[v] || s[0]); }

Использовать с

<script> document.write(getNumberWithOrdinal(day)); </script>
person John    schedule 10.01.2019