# Häufigkeit der Buchstaben und Zahlen in einem Text



## tami_la (18. Nov 2018)

Hey!
Ich muss bei meiner Hausübung ein Programm Erstellen, dass die Häufigkeit der Buchstaben und Zahlen analysiert.
Dazu habe ich folgenden Code mithilfe der ASCII-Tabelle geschrieben. Leider funktioniert diese aber nicht . Programmiere erst seit ein Monat und bin nun an meine Grenzen gestoßen.  Hab so ein Verdacht, dass höchstwahrscheinlich bei der Zeile 31 etw. nicht passt, bin mir aber nicht sicher.
Code:


```
public class Buchstabenanalyse {
   
    public static void main(String[] args){
       
        int [] input= new int[36];
       
        Out.print("Bitte Text eingeben:");
         input= readText();
         printAnalysis(input); //Output Buchstabenstatistik
       
       
    }
       
       
    public static int[] readText(){
           
        int pos=0; //position
        int[]alphabet= new int[36];
               
        char text=In.read(); //inputtext
        //testing individual elements from the input
        //from slot 0 to 25
        while(text != '\n'){
            if (text>='A' && text<='Z'){ //between 65 and 90
                pos=text-'A';
                alphabet[pos]++;
            }else if(text >='a' && text<='z'){ //between 97 and 122
                pos=text-'a';
                alphabet[pos]++;
        //from slot 26 to 36 ?? Does not work, why?   
            }else if(text>='0' && text<='9'){ //between 48 and 57
                pos=text-'9';
                alphabet[pos]++;
            }
            text= In.read();
        }
                return alphabet;
    }
   
    public static void printAnalysis(int[] numLetters){
       
        char unit= 'A';
       
        if(numLetters.length==36){ //number Letters
            Out.println("Buchstabenstatistik\n------------------- ");
           
            for(int i=0; i<numLetters.length; i++){
                Out.println(unit +" "+  "kommt" + " "+ numLetters[i] + " " + "x  vor");
                unit++;
            }
        }else {
            return; //nicht möglich
        }
       
    }
```


----------



## mihe7 (18. Nov 2018)

So verkehrt sieht das alles auf den ersten Blick nicht aus. Lediglich bei den Zahlen gibt es Probleme. Die Position müsstest Du - wie den Buchstaben auch - relativ zur ersten Zahl bestimmen, d. h. text - '0' und nicht text - '9'. Damit ist pos eine Zahl zwischen 0 und 9. Naja, und wie Du diese Zahl in den Bereich von 26 bis 35 bekommst, sollte klar sein.

Bei der Ausgabe musst Du ebenfalls für den Bereich von 0 bis 25 (incl) beim 'A' beginnen, für die Zahlen (Bereich ab 26) dagegen mit '0'.


----------



## Senftube (19. Nov 2018)

Hallo,
Von ASCII auszugehen ist heute nicht mehr so angebracht (unicode ?). Und die Position eines Zeichens in einer ominösen Tabelle mitVermutmutungen zu berechnen, sollte man auch nicht machen.
Zur Klassifizierung gibt es
in der Character-Klasse diverse is* Funktionen mit der du ein 16bit-char testen kannst z.b. so:


```
int cntLetter = 0,cntDigit=0;
   char c;
   String str = "dgze45afag";
   for (int i=0; i < str.length();i++)
    {
       c = str.charAt(i);
       if (Character.isDigit(c)) cntDigit++;
       if (Character.isLetter(c)) cntLetter++;  
    }
   System.out.println("Zahlen: " + cntDigit + " Buchstaben: " + cntLetter);
```


```
Zahlen: 2 Buchstaben: 8
```


----------



## Flown (19. Nov 2018)

Bitte Code-Tags verwenden: [code=java]//JAVA CODE HERE[/code]


----------



## mihe7 (19. Nov 2018)

Senftube hat gesagt.:


> Und die Position eines Zeichens in einer ominösen Tabelle mitVermutmutungen zu berechnen, sollte man auch nicht machen.


Welche ominöse Tabelle?


----------



## httpdigest (19. Nov 2018)

Naja, das Ganze sieht schon ziemlich verkehrt aus.
Das Problem ist, dass du ja die drei Bereiche 'A'-'Z', 'a'-'z' und '0'-'9' auf denselben Zahlenbereich 0-n als Index abbildest. Das heißt, du kannst hinterher gar nicht mehr entscheiden, wenn in deinem Alphabet-Array bei Position 0 nun eine 4 steht, ob das nun vier 'A's oder vier 'a's oder vier Nullen oder irgendeine Kombination daraus waren. Du solltest schon die tatsächliche Breite von ASCII nehmen (wenn es denn ASCII sein soll).


----------



## Senftube (19. Nov 2018)

mihe7 hat gesagt.:


> Welche ominöse Tabelle?


Ich meinte die Ascii-Tabelle und das rum-gerechne wo welche Bereiche sind. Die Tastatur hat doch auch andere Zeichen, die nicht in Ascii vorhanden sind. z.B das Euro-Zeichen oder Umlaute ??
Das Char-Encoding ist i.d.R Unicode als UTF-8 oder UTF-16 (gerne bei .ini-Dateien verwendet) - allenfalls noch ISO-8859-2 in Europa. Da ein char in Java - 16 bit groß ist, sollte man sich mehr mit 7bit Darstellungen aus dem Anfang der Computergeschichte befassen.


----------



## mihe7 (19. Nov 2018)

Einmal davon abgesehen, dass er die ASCII-Tabelle überhaupt nicht verwendet (er prüft Codepoints und bildet diese auf ein Array ab), die ersten Codepoints in Unicode mit der ASCII-Tabelle übereinstimmen und das Encoding hier überhaupt keine Rolle spielt, verstehen wir seine Aufgabe vermutlich unterschiedlich. 

Wenn ich mir den Hintergrund ("Hausübung"), das Niveau der Aufgabe und seinen Code ansehe, möchte er einfach wissen, wie oft die Buchstaben A-Z (Groß-/Kleinschreibung egal) bzw. die Ziffern 0 bis 9 in einem Text vorkommen.


----------



## httpdigest (19. Nov 2018)

Ja, und genau das tut er (bzw. sie) ja eben nicht, da - wie gesagt - A-Z, a-z und 0-9 auf dasselbe Intervall abgebildet wird (bzw. bei 0-9 die ersten 10 Zeichen von A-Z bzw. a-z). Durch eben die Subtraktion von 'A', 'a' bzw. '0' in den jeweiligen Fällen.


----------



## mihe7 (19. Nov 2018)

httpdigest hat gesagt.:


> Ja, und genau das tut er (bzw. sie) ja eben nicht, da - wie gesagt


Das ist doch ein alter Hut 
https://www.java-forum.org/thema/ha...und-zahlen-in-einem-text.183196/#post-1167365


----------



## httpdigest (19. Nov 2018)

Oh mann... , hast 100% Recht. Hatte wohl einen meiner doofen Momente heute.


----------



## Senftube (19. Nov 2018)

Hi,
ja die Postings zeigen, das jeder die Fragestellung selbst auf seine Weise interpretiert - das ist sehr menschlich.
Der erste Satz von ihr lautet ja: ....die Häufigkeit der Buchstaben und Zahlen analysiert.
Da ist ja von A-Z und a-z und 0-9 ja gar keine Rede !!. Das hat jeder so aufgegriffen weil sie auf diese (falsche) Fährte gesetzt hat und reagiert darauf (sehr höfilch aber Thema verfehlt)
tamil-la muss ja sehr geschockt sein auf so eine einfache Frage so unterschiedliche Antworten zu erhalten.
Gerade wenn sie erst anfängt sollte man ihr mehr helfen.
Ich sag ganz vorsichtig, dass sie mit der ASCII-Schiene auf den falschen Weg geraten ist..ohne das als Kritk zu verstehen. (Es ist gut zu wissen was ASCII einmal war und dass es heute niemanden mehr interresiert. ).
Wenn sie aus einer Eingabe einen String bestehend aus 16-bit Characters hat, dann sollte sie die Funktionalitäten
von Character.is* auch benutzen - ist doch egal was ß für eine Nummer in der ASCII Tabelle hat und ob es das Zeichen dort gibt ?. Was macht man mit dem russischen Zeichenkette: In China wird nicht mit € bezahlt. Ein Jahr hat 12 Monate.
String str = "В Китае не платят €. Один год - 12 месяцев.";
Ist denn jetzt д im Bereich a-z oder eher A-Z ? und ist я im Bereich 0-9 ?
Sorry - einfach lächerlich


----------



## mihe7 (20. Nov 2018)

Was die Aufgabe betrifft, hast Du vollkommen Recht: Ihr Code passt nicht zur Beschreibung 

Bzgl. ASCII bzw. dessen SBCS-Erweiterungen bin ich allerdings anderer Meinung. Die Aussage "gut zu wissen was ASCII einmal war und dass es heute niemanden mehr interresiert" wird der Bedeutung des ASCII-Zeichensatzes nicht gerecht. Dieser _ist_ nach wie vor die Basis für eine Vielzahl von Zeichensätzen. Es ist auch nicht alles Desktop oder Web, nicht alles hat praktisch beliebig viel RAM und vieles kommt mit 7/8 Bit pro Zeichen aus, weil auch nicht alles multilingual (global) sein muss. 



Senftube hat gesagt.:


> Wenn sie aus einer Eingabe einen String bestehend aus 16-bit Characters hat, dann sollte sie die Funktionalitäten
> von Character.is* auch benutzen


Ja, wenn man feststellen will, in welche Kategorie ein Zeichen fällt und dafür eine Funktion zur Verfügung gestellt bekommt, dann sollte man diese nutzen. Das steht außer Frage und gilt ganz unabhängig von der Bit-Länge. 



Senftube hat gesagt.:


> Ist denn jetzt д im Bereich a-z oder eher A-Z ? und ist я im Bereich 0-9 ?


In keinem, weil д im Zeichensatz A_Z0_9 nicht vorkommt


----------



## Senftube (20. Nov 2018)

Hallo mihe7
Alles gut. Ich habe ja nix gegen ASCII - ist in jedem Zeichensatz als Grundstock mit der gleichen Position vorhanden. Nur zur Erinnerung: In UTF-8 wird für einfache ASCII-Zeichen auch nur ein Byte "ver(sch)wendet" - ist also nicht Plattenplatz-verschwenderischer als ASCII oder ANSI (ISO8599). Wenn eine Zeichenkette* in Java* ials String zur Verfügung steht braucht sie sowieso pro Zeichen 2 Byte (anders als in C) auch wenn ASCII-Zeichen dabei sind, die nur 1 Byte benötigen würden  - also warum sich dann auf ASCII beschränken ? Oder anders: Schade eigentlich, dass jedes ASCII Zeichen 1 ungenutztes Byte verschwendet, was sowieso da ist 
PS: Hab den russischen Satz spasseshalber mal mit isLetter und isDigit() ausgewertet

```
int cntLetter = 0,cntDigit=0;
   char c;
   String str = "В Китае не платят €. Один год - 12 месяцев.";
   // In China wird nicht mit € bezahlt. Ein Jahr hat 12 Monate.
   for (int i=0; i < str.length();i++)
    {
       c = str.charAt(i);
      [B] System.out.format("Der char %c hat den wert %d = 0x%04x%n",c,(int)c,(int)c);[/B]
       if (Character.isLetter(c)) cntLetter++;   
       else if (Character.isDigit(c)) cntDigit++;
    }
   System.out.println("Zahlen: " + cntDigit + " Buchstaben: " + cntLetter);
```
Das Ergebnis ist Zahlen: 2 Buchstaben: 28 (weil eben В Китае не платят... doch Buchstaben sind auch wenn sie nicht in der ASCII-Tabelle aufgeführt sind.)
An der Ausgabe sieht man -wie erwartet-, dass nur wenige Ascii-Zeichen dabei sind. Aber isLetter() weis, dass das Zeichen 1080 ein Zeichen und keine Ziffer ist. Auszug:
	
	
	
	





```
Der char и hat den wert 1080 = 0x0438
           Der char н hat den wert 1085 = 0x043d
           Der char   hat den wert 32 = 0x0020
           Der char г hat den wert 1075 = 0x0433
           Der char о hat den wert 1086 = 0x043e
           Der char д hat den wert 1076 = 0x0434
           [I]Der char   hat den wert 32 = 0x0020
           Der char - hat den wert 45 = 0x002d
           Der char   hat den wert 32 = 0x0020
           Der char 1 hat den wert 49 = 0x0031
           Der char 2 hat den wert 50 = 0x0032
           Der char   hat den wert 32 = 0x0020[/I]
           Der char м hat den wert 1084 = 0x043c
```


----------



## httpdigest (20. Nov 2018)

Senftube hat gesagt.:


> Wenn eine Zeichenkette* in Java* ials String zur Verfügung steht braucht sie sowieso pro Zeichen 2 Byte


Nope. https://openjdk.java.net/jeps/254


----------



## mihe7 (20. Nov 2018)

Senftube hat gesagt.:


> In UTF-8 wird für einfache ASCII-Zeichen auch nur ein Byte "ver(sch)wendet" - ist also nicht Plattenplatz-verschwenderischer als ASCII oder ANSI (ISO8599).


Gilt aber nur bis 7-Bit  Darum geht es aber nicht alleine: wer ASCII will, wird nicht schreiben, dass Unicode-Zeichensatz in UTF-8-Kodierung verwendet wird, verbunden mit der Einschränkung auf die ersten 128 Codepoints - obwohl, den Marketing-Heinis ist alles zuzutrauen  



Senftube hat gesagt.:


> Wenn eine Zeichenkette* in Java* ials String zur Verfügung steht braucht sie sowieso pro Zeichen 2 Byte (anders als in C) auch wenn ASCII-Zeichen dabei sind, die nur 1 Byte benötigen würden - also warum sich dann auf ASCII beschränken ?


Das war lange Zeit so. Im Gegenzug darf man Java das Interning zugute halten.



httpdigest hat gesagt.:


> Nope. https://openjdk.java.net/jeps/254


Huch, ich dachte es wäre UTF-8 geworden... Gut, dass wir darüber gesprochen haben


----------



## Senftube (20. Nov 2018)

Hallo httpdigest,
danke für den Link. Sehr interessant, dass es da eine Arbeitsgruppe dafür gibt. Hat mich eigentlich schon immer seit Java's Urzeiten gewundert, dass 16 bit für ein char so niemanden "aufgestoßen" ist. Habs aber als state-of-the-art so angenommen (so wie auch viele Leute keine Tastatur mehr verwenden sondern mit ihren fettigen Fingern sensible Glasscheiben verschmutzen und trotzdem was buntes zu sehen kriegen .  Auch mit etwas Herzblut aus den 80 er Jahren mit C denke ich, dass die 1 Byte-Geschichte für ein char einfach und unwiderbringlich vorbei ist, da ja alle Welt mit ihren kulturbedingten-Zeichensätzen zurechtkommen *muss*, an die die Computerpioniere gar nicht dachten oder sich nicht vorstellen konnten, dass ausserhalb USA jemals jemand einen Computer haben wird (daher war ASCII der Schuß aus der Hüfte und gut für "ähnliche" Kulturen)
Ich denke das dieses Project "Optimizing character storage for memory" ein lobenswerter Versuch ist, das verschwendete Byte der ASCII-Zeichen im RAM zu "retten". Weltweit gesehen, wird ASCII wohl keinerlei Interesse haben- daher ist das Optimierungspotential dieses Projekts gleich null.
Dank UTF-8 werden die Daten ja auf Platte kompakt abgelegt, wenns geht 1 Byte ansonsten mehr Bytes -  der Königsweg überhaupt -vor ever. Winzigweich ziert sich da (und bevorzugt ihr ANSI, am besten für jedes Dorf ein eigene Ausprägung) da sie der Untersuchung der ersten Bits nicht so recht traut (bzgl Performance und UTF-8 ist ja auch gar von uns - ganz böse also) und haut alles was schnell gehen soll als UTF-16 raus (manche .ini-dateien)
Java macht beim "Einlesen" von Strings da einen Schlussstrich und sagt - ne danke, ich prügel jedes Zeichen in 2 bytes rein- fertig - ja das ist einfach so prefekt- 1 byte Ende aus. Wenn ich an die zeiten in Unix mit
wide-characters denke, finde ich dass das eine vernünftige, zukunftsweisende Entscheidung war und das Leben für jeden Java-Programmierer einfacher macht - nee danke, niemals nicht mehr, keine wide characters mehr, nie nicht (mehrfache Bayrische Verneinung).
Hab die technischen Details in deinem Link nur quer gelesen, letztendlich soll wohl eine Speicherstrategie erfolgen, die transparent für Java-Anwender/programierer ist (Ist die Frage, ob eine kleinerer Ram-Bedarf eine erhöhte CPU Belastung der JRE rechtfertig) . Na warten wir es ab.
Sorry für den langen Post, aber das musste jetzt mal sein.


----------



## httpdigest (20. Nov 2018)

Du hast auch das "Status: Closed/Delivered" und das "Release: 9" gesehen? Falls du also mindestens ein JRE 9 verwendest, ist das schon drin.


----------



## Senftube (20. Nov 2018)

Super ist schon umgesetzt, werde has mal auf einer 9er Spielwiese ausprobieren und benchmarks machen.
Danke !!!!  Bin ja tierisch gespannt und mich dann für die internen Konzepte interrsieren.


----------



## MoxxiManagarm (21. Nov 2018)

Weil ich Lust hatte auch mal ein wenig 'advanced' herumzuspielen:


```
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;


public class CharacterTypeDemo {
    public static void main(String... args) {
        // available Character typpes in Character class (Reflection)
        Map<Byte, String> characterTypes = Arrays.stream(Character.class.getFields())
                .filter(field -> field.getType() == byte.class)
                .filter(field -> ! field.getName().startsWith("DIRECTIONALITY"))
                .collect(Collectors.toMap(field -> {
                        try {
                            return field.getByte('0');
                        } catch (IllegalArgumentException | IllegalAccessException ex) {
                            System.out.println("Upps, something went wrong.");
                        }

                        return (byte)0;
                    }, Field::getName));
       
        // text to analyze
        String text = "Helló Wôrld! Did you know? Java is cool² in 2018 ;-)";
        System.out.println("Analyzing text: ");
        System.out.println(text + '\n');
       
        // counting by Type
        Map<Integer, Long> typeCounter = text.codePoints()
                .mapToObj(Integer::valueOf)
                .collect(Collectors.groupingBy(Character::getType, Collectors.counting()));
       
        // printing with lookup
        typeCounter.forEach((k, v) ->
                System.out.println("Type " + characterTypes.get(k.byteValue()) + " occured " + v + " times."));
    }
}
```


```
Analyzing text: 
Helló Wôrld! Did you know? Java is cool² in 2018 ;-)

Type UPPERCASE_LETTER occured 4 times.
Type LOWERCASE_LETTER occured 28 times.
Type DASH_PUNCTUATION occured 1 times.
Type END_PUNCTUATION occured 1 times.
Type OTHER_PUNCTUATION occured 3 times.
Type DECIMAL_DIGIT_NUMBER occured 4 times.
Type OTHER_NUMBER occured 1 times.
Type SPACE_SEPARATOR occured 10 times.
```


----------

