Подтвердить что ты не робот

Вставка запятых в числовую строку

Привет, я пытаюсь выполнить обратный поиск регулярных выражений на строке, чтобы разделить ее на группы из 3-х цифр. Насколько я могу видеть из документации AS3 поиск в обратном порядке невозможен в двигателе reg ex.

Цель этого упражнения - вставить триплетные запятые в число, подобное так:

10000000 => 10,000,000

Я собираюсь сделать это так:

string.replace(/(\d{3})/g, ",$1")

Но это неверно из-за того, что поиск не происходит со спины, а замена $1 будет работать только для первого матча.

У меня возникает ощущение, что мне будет лучше выполнять эту задачу, используя цикл.

UPDATE:

Из-за того, что AS3 не поддерживает lookahead, я решил это.

public static function formatNumber(number:Number):String
{
    var numString:String = number.toString()
    var result:String = ''

    while (numString.length > 3)
    {
        var chunk:String = numString.substr(-3)
        numString = numString.substr(0, numString.length - 3)
        result = ',' + chunk + result
    }

    if (numString.length > 0)
    {
        result = numString + result
    }

    return result
}
4b9b3361

Ответ 1

Если ваш язык поддерживает утверждения postive lookahead, я думаю, что следующее regex будет работать:

(\d)(?=(\d{3})+$)

Продемонстрировано в Java:

import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class CommifyTest {

    @Test
    public void testCommify() {
        String num0 = "1";
        String num1 = "123456";
        String num2 = "1234567";
        String num3 = "12345678";
        String num4 = "123456789";

        String regex = "(\\d)(?=(\\d{3})+$)";

        assertEquals("1", num0.replaceAll(regex, "$1,"));
        assertEquals("123,456", num1.replaceAll(regex, "$1,"));
        assertEquals("1,234,567", num2.replaceAll(regex, "$1,"));
        assertEquals("12,345,678", num3.replaceAll(regex, "$1,"));
        assertEquals("123,456,789", num4.replaceAll(regex, "$1,"));    
    }    
}

Следующая ссылка

Ответ 2

Найдено на http://gskinner.com/RegExr/

Сообщество > Thousands separator

Выкройка: /\d{1,3}(?=(\d{3})+(?!\d))/g

Заменить: $&,

trace ( String("1000000000").replace( /\d{1,3}(?=(\d{3})+(?!\d))/g , "$&,") );

Это сработало!

Ответ 3

Если ваш двигатель регулярных выражений имеет положительные результаты, вы можете сделать что-то вроде этого:

string.replace(/(\d)(?=(\d\d\d)+$)/, "$1,")

Если позитивный lookahead (? =...) означает, что регулярное выражение соответствует только выражению lookahead...

(Обратите внимание, что обратные выражения не всегда очень эффективны.)

Ответ 4

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

Я собрал много ответов здесь в тестовом классе (и включил решение из этого blog и ответ моего собственного называемый commaify) и отформатировал их согласованным способом для простого сравнения:

package
{
    public class CommaNumberSolutions
    {   
        public static function commaify( input:Number ):String
        {
            var split:Array = input.toString().split( '.' ),
                front:String = split[0],
                back:String = ( split.length > 1 ) ? "." + split[1] : null,
                n:int = input < 0 ? 2 : 1,
                commas:int = Math.floor( (front.length - n) / 3 ),
                i:int = 1;

            for ( ; i <= commas; i++ )
            {
                n = front.length - (3 * i + i - 1);
                front = front.slice( 0, n ) + "," + front.slice( n );
            }

            if ( back )
                return front + back;
            else
                return front;
        }

        public static function getCommaString( input:Number ):String
        {
            var s:String = input.toString();

            if ( s.length <= 3 )
                return s;

            var i:int = s.length % 3;

            if ( i == 0 )
                i = 3;

            for ( ; i < s.length; i += 4 )
            {
                var part1:String = s.substr(0, i);
                var part2:String = s.substr(i, s.length);
                s = part1.concat(",", part2);
            }

            return s;
        }

        public static function formatNumber( input:Number ):String
        {
            var s:String = input.toString()
            var result:String = ''

            while ( s.length > 3 )
            {
                var chunk:String = s.substr(-3)
                s = s.substr(0, s.length - 3)
                result = ',' + chunk + result
            }

            if ( s.length > 0 )
                result = s + result

            return result
        }

        public static function commaCoder( input:Number ):String
        {
            var s:String = "";
            var len:Number = input.toString().length;

            for ( var i:int = 0; i < len; i++ )
            { 
                if ( (len-i) % 3 == 0 && i != 0)
                    s += ",";

                s += input.toString().charAt(i);
            }
            return s;
        }

        public static function regex1( input:Number ):String
        {
            return input.toString().replace( /-{0,1}(\d)(?=(\d\d\d)+$)/g, "$1," );
        }

        public static function regex2( input:Number ):String
        {
            return input.toString().replace( /-{0,1}\d{1,3}(?=(\d{3})+(?!\d))/g , "$&,")
        }

        public static function addCommas( input:Number ):String
        {
            var negative:String = "";
            if ( input < 0 )
            {
                negative = "-";
                input = Math.abs(input);
            }

            var s:String = input.toString();
            var results:Array = s.split(/\./);
            s = results[0];

            if ( s.length > 3 )
            {
                var mod:Number = s.length % 3;
                var output:String = s.substr(0, mod);
                for ( var i:Number = mod; i < s.length; i += 3 )
                {
                    output += ((mod == 0 && i == 0) ? "" : ",") + s.substr(i, 3);
                }

                if ( results.length > 1 )
                {
                    if ( results[1].length == 1 )
                        return negative + output + "." + results[1] + "0";
                    else
                        return negative + output + "." + results[1];
                }
                else
                    return negative + output;
            }
            if ( results.length > 1 )
            {
                if ( results[1].length == 1 )
                    return negative + s + "." + results[1] + "0";
                else
                    return negative + s + "." + results[1];
            }
            else
                return negative + s;
        }
    }
}

Затем я тестировал каждый на точность и производительность:

package
{    
    public class TestCommaNumberSolutions
    {
        private var functions:Array;

        function TestCommaNumberSolutions()
        {
            functions = [
                { name: "commaify()", f: CommaNumberSolutions.commaify },
                { name: "addCommas()", f: CommaNumberSolutions.addCommas },
                { name: "getCommaString()", f: CommaNumberSolutions.getCommaString },
                { name: "formatNumber()", f: CommaNumberSolutions.formatNumber },
                { name: "regex1()", f: CommaNumberSolutions.regex1 },
                { name: "regex2()", f: CommaNumberSolutions.regex2 },
                { name: "commaCoder()", f: CommaNumberSolutions.commaCoder }
            ];
            verify();
            measure();
        }

        protected function verify():void
        {
            var assertions:Array = [ 
                { input: 1, output: "1" },
                { input: 21, output: "21" },
                { input: 321, output: "321" },
                { input: 4321, output: "4,321" },
                { input: 54321, output: "54,321" },
                { input: 654321, output: "654,321" },
                { input: 7654321, output: "7,654,321" },
                { input: 987654321, output: "987,654,321" },
                { input: 1987654321, output: "1,987,654,321" },
                { input: 21987654321, output: "21,987,654,321" },
                { input: 321987654321, output: "321,987,654,321" },
                { input: 4321987654321, output: "4,321,987,654,321" },
                { input: 54321987654321, output: "54,321,987,654,321" },
                { input: 654321987654321, output: "654,321,987,654,321" },
                { input: 7654321987654321, output: "7,654,321,987,654,321" },
                { input: 87654321987654321, output: "87,654,321,987,654,321" },
                { input: -1, output: "-1" },
                { input: -21, output: "-21" },
                { input: -321, output: "-321" },
                { input: -4321, output: "-4,321" },
                { input: -54321, output: "-54,321" },
                { input: -654321, output: "-654,321" },
                { input: -7654321, output: "-7,654,321" },
                { input: -987654321, output: "-987,654,321" },
                { input: -1987654321, output: "-1,987,654,321" },
                { input: -21987654321, output: "-21,987,654,321" },
                { input: -321987654321, output: "-321,987,654,321" },
                { input: -4321987654321, output: "-4,321,987,654,321" },
                { input: -54321987654321, output: "-54,321,987,654,321" },
                { input: -654321987654321, output: "-654,321,987,654,321" },
                { input: -7654321987654321, output: "-7,654,321,987,654,321" },
                { input: -87654321987654321, output: "-87,654,321,987,654,321" },
                { input: .012345, output: "0.012345" },
                { input: 1.012345, output: "1.012345" },
                { input: 21.012345, output: "21.012345" },
                { input: 321.012345, output: "321.012345" },
                { input: 4321.012345, output: "4,321.012345" },
                { input: 54321.012345, output: "54,321.012345" },
                { input: 654321.012345, output: "654,321.012345" },
                { input: 7654321.012345, output: "7,654,321.012345" },
                { input: 987654321.012345, output: "987,654,321.012345" },
                { input: 1987654321.012345, output: "1,987,654,321.012345" },
                { input: 21987654321.012345, output: "21,987,654,321.012345" },
                { input: -.012345, output: "-0.012345" },
                { input: -1.012345, output: "-1.012345" },
                { input: -21.012345, output: "-21.012345" },
                { input: -321.012345, output: "-321.012345" },
                { input: -4321.012345, output: "-4,321.012345" },
                { input: -54321.012345, output: "-54,321.012345" },
                { input: -654321.012345, output: "-654,321.012345" },
                { input: -7654321.012345, output: "-7,654,321.012345" },
                { input: -987654321.012345, output: "-987,654,321.012345" },
                { input: -1987654321.012345, output: "-1,987,654,321.012345" },
                { input: -21987654321.012345, output: "-21,987,654,321.012345" }
            ];

            var i:int;
            var len:int = assertions.length;
            var assertion:Object;
            var f:Function;
            var s1:String;
            var s2:String;

            for each ( var o:Object in functions )
            {
                i = 0;
                f = o.f;
                trace( '\rVerify: ' + o.name ); 
                for ( ; i < len; i++ )
                {
                    assertion = assertions[ i ];
                    s1 = f.apply( null, [ assertion.input ] );
                    s2 = assertion.output;
                    if ( s1 !== s2 )
                        trace( 'Test #' + i + ' Failed: ' + s1 + ' !== ' + s2 );
                }
            }

        }

        protected function measure():void
        {
            // Generate random inputs
            var values:Array = [];
            for ( var i:int = 0; i < 999999; i++ ) {
                values.push( Math.random() * int.MAX_VALUE * ( Math.random() > .5 ? -1 : 1) );
            }

            var len:int = values.length;
            var stopwatch:Stopwatch = new Stopwatch;
            var s:String;
            var f:Function;
            trace( '\rTesting ' + len + ' random values' );
            // Test each function
            for each ( var o:Object in functions )
            {
                i = 0;
                s = "";
                f = o.f;
                stopwatch.start();
                for ( ; i < len; i++ ) {
                    s += f.apply( null, [ values[i] ] ) + " ";
                }
                stopwatch.stop();
                trace( o.name + '\t\ttook ' + (stopwatch.elapsed/1000) + 's' ); //(stopwatch.elapsed/len) + 'ms'
            }
        }
    }
}

import flash.utils.getTimer;

class Stopwatch
{
    protected var startStamp:int;
    protected var stopStamp:int;
    protected var _started:Boolean;
    protected var _stopped:Boolean;

    function Stopwatch( startNow:Boolean = true ):void
    {
        if ( startNow ) 
            start();
    }

    public function start():void
    {
        startStamp = getTimer();
        _started = true;
        _stopped = false;
    }

    public function stop():void
    {
        stopStamp = getTimer();
        _stopped = true;
        _started = false;
    }

    public function get elapsed():int
    {
        return ( _stopped ) ? stopStamp - startStamp : ( _started ) ? getTimer() - startStamp : 0;
    }

    public function get started():Boolean
    {
        return _started;
    }

    public function get stopped():Boolean
    {
        return _stopped;
    }
}

Из-за отсутствия точности AS3 с большими числами каждый класс не прошел эти тесты:

Test #15 Failed: 87,654,321,987,654,320 !== 87,654,321,987,654,321
Test #31 Failed: -87,654,321,987,654,320 !== -87,654,321,987,654,321
Test #42 Failed: 21,987,654,321.012344 !== 21,987,654,321.012345
Test #53 Failed: -21,987,654,321.012344 !== -21,987,654,321.012345

Но только две функции прошли все остальные тесты: commaify() и addCommas().

Тесты производительности показывают, что commaify() является наиболее предварительным для всех решений:

Testing 999999 random values
commaify()        took 12.411s
addCommas()       took 17.863s
getCommaString()  took 18.519s
formatNumber()    took 14.409s
regex1()          took 40.654s
regex2()          took 36.985s

Кроме того, функция commaify() может быть расширена до включения аргументов для десятичной длины и нулевого заполнения десятичной части - она ​​также превосходит остальных в 13.128s:

public static function cappedDecimal( input:Number, decimalPlaces:int = 2 ):Number
{
    if ( decimalPlaces == 0 ) 
        return Math.floor( input );

    var decimalFactor:Number = Math.pow( 10, decimalPlaces );

    return Math.floor( input * decimalFactor ) / decimalFactor;
}

public static function cappedDecimalString( input:Number, decimalPlaces:int = 2, padZeros:Boolean = true ):String
{
    if ( padZeros )
        return cappedDecimal( input, decimalPlaces ).toFixed( decimalPlaces );
    else
        return cappedDecimal( input, decimalPlaces ).toString();
}

public static function commaifyExtended( input:Number, decimalPlaces:int = 2, padZeros:Boolean = true ):String
{
   var split:Array = cappedDecimalString( input, decimalPlaces, padZeros ).split( '.' ),
       front:String = split[0],
       back:String = ( split.length > 1 ) ? "." + split[1] : null,
       n:int = input < 0 ? 2 : 1,
       commas:int = Math.floor( (front.length - n) / 3 ),
       i:int = 1;

   for ( ; i <= commas; i++ )
   {
       n = front.length - (3 * i + i - 1);
       front = front.slice( 0, n ) + "," + front.slice( n );
   }

   if ( back )
       return front + back;
   else
       return front;
}

Итак, я бы предложил, чтобы commaify() удовлетворяет требованиям универсальности и производительности, хотя, конечно, не самый компактный или элегантный.

Ответ 5

Это действительно не лучшее использование RegEx... Я не знаю функции форматирования чисел, но этот поток кажется, обеспечивает решение.

function commaCoder(yourNum):String {
    //var yourNum:Number = new Number();
    var numtoString:String = new String();
    var numLength:Number = yourNum.toString().length;
    numtoString = "";

    for (i=0; i<numLength; i++) { 
        if ((numLength-i)%3 == 0 && i != 0) {
            numtoString += ",";
        }
        numtoString += yourNum.toString().charAt(i);
        trace(numtoString);
    }
    return numtoString;
}

Если вы действительно настаиваете на использовании RegEx, вы можете просто изменить строку, применить функцию замены RegEx, а затем отменить ее обратно.

Ответ 6

A sexeger подходит для этого. Короче говоря, sexeger - это обратное регулярное выражение против обращенной строки, в которой вы меняете результат. Это, как правило, более эффективно, чем альтернатива. Вот какой псевдокод для того, что вы хотите сделать:

string = reverse string
string.replace(/(\d{3})(?!$)/g, "$1,")
string = reverse string

Вот реализация Perl

#!/usr/bin/perl

use strict;
use warnings;

my $s = 13_456_789;

for my $n (1, 12, 123, 1234, 12345, 123456, 1234567) {
    my $s = reverse $n;
    $s =~ s/([0-9]{3})(?!$)/$1,/g;
    $s = reverse $s;
    print "$s\n";
}

Ответ 7

Возможно, вы захотите рассмотреть NumberFormatter

Ответ 8

//Это простой код, и он отлично работает...:)

import java.util.Scanner;

public class NumberWithCommas {

    public static void main(String a[]) {
        Scanner sc = new Scanner(System.in);

        String num;

        System.out.println("\n enter the number:");

        num = sc.next();

        printNumber(num);
    }

    public static void printNumber(String ar) {
        int len, i = 0, temp = 0;
        len = ar.length();
        temp = len / 3;
        if (len % 3 == 0)
            temp = temp - 1;
        len = len + temp;
        char[] ch = ar.toCharArray();
        char[] ch1 = new char[len];
        for (int j = 0, k = (ar.length() - 1); j < len; j++)
        {
            if (i < 3)
            {
                ch1[j] = ch[k];
                i++;
                k--;
            }
            else
            {
                ch1[j] = ',';
                i = 0;
            }
        }
        for (int j = len - 1; j >= 0; j--)
            System.out.print(ch1[j]);
        System.out.println("");
    }
}

Ответ 9

Попробуйте этот код. это простая и лучшая производительность.

var reg:RegExp=/\d{1,3}(?=(\d{3})+(?!\d))/g;
var my_num:Number = 48712694;
var my_num_str:String = String(my_num).replace(reg,"$&,");
trace(my_num_str);

:: Выход::

48,712,694