• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

printf zahl von 1222111.55 nach 1.222.111,55

lars22

Newbie
Hallo liebe Linuxfans,

ich suche nach einer Möglichkeit eine Zahl zu formatieren.
Kann man mit dem printf Befehl eine Zahl von 1222111.55 nach 1.222.111,55 formatieren?

Danke vorab und viele Grüße,
Lars
 

regexer

Advanced Hacker
printf selbst kennt wohl keine Möglichkeit. Ansonsten findet google für "thousands separator" unter anderem

sed: http://www.unix.com/shell-programming-scripting/53089-thousands-separator-3.html
Perl: http://www.perlmonks.org/?node_id=117697
 

abgdf

Guru
Hi,

das mußte ich schon sehr oft schreiben: Hier meine aktuelle Lösung in Python:
Code:
#!/usr/bin/env python
#-*- coding: iso-8859-1 -*-

import sys

def eur(a):

    """ Changing float to EUR-string. """

    b = "%.2f" % a

    b = b.replace('.',',')

    c = b.split(",")

    return thpoints(c[0]) + "," + c[1]

   
def thpoints(a):

    """ Returns a string with points for thousands in high values ...
        ... from a positive or negative int. """

    a = int(a)

    neg = False

    if a < 0:
        neg = True
        a = a * -1

    a = str(a)

    b = []

    for i in a: 
        b.append(i)

    x = len(b)

    while x > 3:
        x -= 3  
        b.insert(x, ".")

    c = "".join(b)

    if neg:
        c = "-" + c

    return c

if len(sys.argv) > 1:
    print eur(float(sys.argv[1]))
Usage:
Code:
./skript.py 1222111.55
Hab's auch in JavaScript, Perl und C ...

Gruß
 

abgdf

Guru
Hi,

hier auch noch meine Version in C (damit kannst Du Dir dann Deinen eigenen Shell-Befehl bauen :) ):
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* eur.c */

char *eur(double v);
char *thpoints(char *a);

int main(int argc, char **argv)
{
    if(argc > 1)
    {
        puts(eur(atof(argv[1])));
    }

    return 0;
}

char *eur(double v)
{
    char *a;
    char *s;
    s = (char *) malloc(50);

    sprintf(s, "%.2f", v);

    a = strstr(s, ".");

    if(a != NULL)
    {
        *a = ',';
    }

    s = thpoints(s);

    return s;
}

char *thpoints(char *a)
{
    char b[50];
    char *c = (char *) malloc(50);
    char *d = strstr(a, ",");

    int i;
    int x = 0;
    int e = 0;

    for(i = strlen(a) - 1; i >= 0; i--)
    {
        if(*(a + i) == ',')
        {
            x = 1;
        }

        if(x == 1 && *(a + i) != ',')
        {
            if((double) (strlen(a) - i - 1) / 3 == (strlen(a) - i - 1) / 3)
            {
                b[e] = '.';
                if(e != 0)
                {
                    e++;
                }
            }
            b[e] = *(a + i);
            e++;
        }
    }

    b[e] = '\0';

    for(i = strlen(b) - 1; i >= 0; i--)
    {
        c[strlen(b) - 1 - i] = b[i];
    }
    strcat(c, d);
        
    free(a);
    return c;
}
(Ja, solange mich der Compiler nicht stoppt, caste ich malloc(); stellt euch auf den Kopf :mrgreen:. Aber, wenn's Speicherlecks gibt, bitte melden.)

Kompiliere mit:
Code:
gcc -g -Wall -Wextra -ansi -pedantic eur.c -o eurstring
Gruß
 

panamajo

Guru
lars22 schrieb:
ich suche nach einer Möglichkeit eine Zahl zu formatieren.
Kann man mit dem printf Befehl eine Zahl von 1222111.55 nach 1.222.111,55 formatieren?
Das kommt auf die Sprache (und leider auch auf die Plattform) an.

In C wird das Dezimalzeichen von der verwendeten Locale bestimmt.
Code:
#include <stdio.h>
#include <locale.h>


int	main	(int argc, char **argv)
{
	char	*locale;
	
	locale = setlocale(LC_NUMERIC, "de_DE.UTF-8");
	printf("Locale: %s\n%'.2f\n", locale, 1222111.55);
	
	locale = setlocale(LC_NUMERIC, "en_US.UTF-8");
	printf("Locale: %s\n%'.2f\n", locale, 1222111.55);
	
	return(0);
}
liefert
Code:
Locale: de_DE.UTF-8
1.222.111,55
Locale: en_US.UTF-8
1,222,111.55
Für komplexere Anwendungen gibt es entsprechende Funktionalität natürlich, z.B. KLocale::formatNumber() bei KDE.

Plattformübergreifend gibts noch libICU...

EDIT: Tausenderseparator funktioniert, man muss nur die Manpage genau lesen (wie jengelh)
 

abgdf

Guru
Hatte negative Zahlen nicht berücksichtigt :oops:.
Hab das zumindest in dem Python-Skript oben noch nachgetragen.

Gruß
 

panamajo

Guru
abgdf schrieb:
(Ja, solange mich der Compiler nicht stoppt, caste ich malloc(); stellt euch auf den Kopf :mrgreen:. Aber, wenn's Speicherlecks gibt, bitte melden.)
Das ist wirklich ganz schlechter Stil und Wasser auf die Mühlen der C Verächter.
 

regexer

Advanced Hacker
In Perl gibt es auch folgende vollständige Lösung (berücksichtigt denke ich sowohl Vorzeichen als auch alles andere):
Code:
echo -1222111.55555 | perl -pe 'if (s/\./,/){1 while s/(\d)(\d{3})(?=[.,])/$1.$2/} else {1 while s/(\d)(\d{3})(?=\D)/$1.$2/}'

EDIT: Bugfix
 
Das geht auch in C, man muss nur mal die Augen aufsperren. `man 3 printf`:
Code:
       For some numeric conversions a radix  character  (`decimal  point')  or
       thousands'  grouping  character  is  used.   The  actual character used
       depends on the LC_NUMERIC part of the locale.  The  POSIX  locale  uses
       `.' as radix character, and does not have a grouping character.  Thus,

               printf("%'.2f", 1234567.89);

       results  in  `1234567.89'  in  the POSIX locale, in `1234567,89' in the
       nl_NL locale, and in `1.234.567,89' in the da_DK locale.
 

abgdf

Guru
... siehe :shock: auch panamajos C-Beispiel oben.

Seltsam aber: Python und Perl scheinen mit "%'.2f" nichts anfangen zu können ...

Gruß
 

panamajo

Guru
abgdf schrieb:
Seltsam aber: Python und Perl scheinen mit "%'.2f" nichts anfangen zu können ...
Deshalb habe ich ja auch darauf hingewiesen dass das von der Sprache abhängt.
Python und Perl werden printf() eigenständig implementieren, ohne Verwendung von printf() aus der C API.

Dto. für PHP, aber da gibt es ja number_format()
 

regexer

Advanced Hacker
jengelh schrieb:
Das geht auch in C, man muss nur mal die Augen aufsperren. `man 3 printf`:
... damit müsste es doch auch das bash-builtin können.

Code:
prompt> locale | grep NUMERIC
LC_NUMERIC="POSIX"
prompt> printf "%'.2f" 1234567.899
1234567.90
prompt> export LC_NUMERIC=de_DE.UTF-8
prompt> printf "%'.2f" 1234567.899
bash: printf: 1234567.899: invalid number
0,00
prompt> printf "%'.2f" 1234567,899
1.234.567,90
prompt>
... naja, da bleibe ich lieber bei POSIX
 
Tut es doch auch.
Code:
$ LC_NUMERIC=de_DE.UTF-8 printf "%'.2f\n" 12345678
12.345.678,00
Selbst das nicht-builtin /usr/bin/printf macht es.

prompt> printf "%'.2f" 1234567.899
bash: printf: 1234567.899: invalid number
0,00
prompt> printf "%'.2f" 1234567,899
1.234.567,90
Ja moment. Von der Eingabe war nie die Rede; die muss weiterhin in POSIX vorliegen. Ausgabe klappt doch mit Thousands-Separator und Komma, also alles ok. Kein Problem in Sicht.
 

abgdf

Guru
... und so geht's (auch) in Python:
Code:
#!/usr/bin/env python

import locale

locale.setlocale(locale.LC_NUMERIC, 'de_DE.UTF-8')

print locale.format("%.2f", 1222111.55, 1)
Hatte den letzten Parameter der Funktion locale.format() (grouping=1) übersehen.
Das passiert mir nun schon zum zweiten Mal :grummel:.

Im Ergebnis wird aber in den Libraries, bzw. dem Modul etwas Ähnliches ablaufen wie in meinen von Hand geschriebenen Funktionen. Insofern gibt sich das nicht viel ...

Gruß
 

andi_

Newbie
mit java gaebs dann noch die variante....

Code:
import java.lang.Object;
import java.text.Format;
import java.text.NumberFormat;

public class format {
public static void main(String[] args) {

String blub = "";

for (int i=0;i<args.length;i++) {
	blub += args[i];
}
try{
	 double d = Double.valueOf(blub);
	 String myString = NumberFormat.getInstance().format(d);
	 System.out.println(myString);
} catch (NumberFormatException e) {}

}
}

wobei man über die Methode getInstance() noch die locale festlegen kann...sonst nimmt er System default
z.B. getInstance(Locale.FRENCH)

Ausgabe waere bei Eingabe "java format 12345.56":

12.345,56
 
Oben