Εισαγωγή στην Java - κεφ. 11

...ασύγχρονα μαθήματα γλώσσας Java

Εισαγωγή στην Java - κεφ. 11

Δημοσίευσηαπό alkismavridis » 17 Νοέμ 2013, 00:48

Προηγούμενο: Exceptions
Επόμενο: Αρχεία


Κείμενα


Σκοπός αυτού του κεφαλαίου είναι να εξοικειωθούμε με τη χρήση των κειμένων, ένα βασικό κομμάτι κάθε γλώσσας προγραμματισμού.
Βασικά εργαλεία μας θα είναι ο βασικός τύπος char, και η κλάση String όπου είδαμε στο προηγούμενο κεφάλαιο.


1. Χαρακτήρες κειμένου - char

Όπως έχουμε δει ένας χαρακτήρας char περιέχει 2 byte πληροφορίας.

Προσοχή: στην C, ο τύπος char είναι 1 byte, στην Java 2!!


Υπάρχουν λοιπόν 2^16 διαφορετικοί char, ή με άλλα λόγια 65536! Καταλαβαίνετε ότι αυτό το νούμερο «αρκεί» για να καλύψει όλα (ή σχεδόν όλα) τα αλφάβητα που χρησιμοποιούν οι άνθρωποι σήμερα, καθώς και ειδικά σύμβολα όπως σημεία στίξης, μαθηματικοί τελεστές κτλ.
Για να μη μακρυγορούμε, υπάρχει «χώρος» για κάθε χαρακτήρα που μπορείτε να σκεφτείτε!


1.1 Κωδικοποίηση χαρακτήρων
Πρέπει να υπάρξει λοιπόν μία αντιστοιχία:
  • Από τη μία έχουμε 2 byte, δηλαδή μία σειρά από 16 ψηφία (0 και 1)
  • Από την άλλη τον χαρακτήρα που θέλουμε να εκτυπώσουμε, δηλαδή μία σειρά από pixel που θέλουμε να εμφανίσουμε στην οθόνη.

Τίθεται λοιπόν η ερώτηση πως αυτά τα δύο συνδέονται. Δηλαδή ποια σειρά από 0 και 1 αντιστοιχεί σε ποιον χαρακτήρα; Και ποιος το καθορίζει αυτό;

Η απάντηση ίσως σας απογοητεύσει. Ακόμα δεν υπάρχει μία καθολική συμφωνία ότι «αυτή η σειρά 0 και 1 αντιστοιχεί σε αυτόν τον χαρακτήρα». Ίσως και να μην υπάρξει ποτέ!
Αντίθετα υπάρχουν πολλοί τέτοιοι «χάρτες» που κάνουν την αντιστοίχηση και ονομάζονται κωδικοποιήσεις χαρακτήρων.

το linux, οι περισσότεροι ιστότοποι, και τα λογισμικά της Apple χρησιμοποιούν μία κωδικοποίηση με όνομα UTF-8.
Η Microsoft έχει τις δικές της κωδικοποιήσεις χαρακτήρων, αγνοώντας (ως συνήθως) όλο τον υπόλοιπο κόσμο. H πιο πρόσφατη (γράφω στις 15-11-2013) ονομάζεται WINDOWS-1252.

Η κωδικοποίηση που χρησιμοποιεί η Java για τις «εσωτερικές» υποθέσεις της ονομάζεται UTF-16. Το 16 φυσικά δηλώνει τα 16 bit πληροφορίας που καταλαμβάνει ο κάθε χαρακτήρας.



1.2 Η κωδικοποίηση UTF-16

Τα παρακάτω σε καμία περίπτωση δε χρειάζεται να τα απομνημονεύσετε. Τα γράφω μόνο για να σας δώσω «μία γεύση» για το πως δουλεύει η αντιστοιχία.
Επίσης το πρόθεμα 0x συμβολίζει δεκαεξαδικό νούμερο.


Σύμφωνα με αυτή τη σύμβαση, οι πρώτοι χαρακτήρες είναι μη εκτυπώσιμοι. Πχ ο πρώτος χαρακτήρας 0000 είναι ο κενός χαρακτήρας, ο 0x000A είναι ο γνωστός μας \n που αλλάζει παράγραφο, ο 0x0020 είναι το κενό διάστημα κ.α.

Από το 0x0021 και άνω αρχίζουν οι εκτυπώσιμοι χαρακτήρες (σύμβολα όπως τα !"#$).
Στην περιοχή 0x0030-0x0039 βρίσκονται τα ψηφία 0-9.
Τα Ελληνικά γράμματα θα τα βρείτε (σε μία περίεργη σειρά) από το 0x0391 και άνω.



1.3 Δήλωση χαρακτήρων
Μπορούμε να δηλώσουμε χαρακτήρες είτε με τον κωδικό τους, είτε απλώς αναγράφοντάς τους:
Μορφοποιημένος Κώδικας: Επιλογή όλων
char ch = 'a';
//ή
char ch = '\u0061'; //τα 4 ψηφία μετά το \u αναπαριστούν δεκαεξαδικό αριθμό!!
//ή
char ch = 97;


Οι τρεις εκφράσεις είναι πανομοιότυπες, γιατί ο λατινικός χαρακτήρας 'a' στο UTF-16 αντιστοιχεί στην τιμή 0x0061 ή 97 στο δεκαδικό σύστημα.
Προσέξτε ότι στις δύο πρώτες περιπτώσεις χρησιμοποιούμε τα μονά εισαγωγικά, και στην δεύτερη βάζουμε το πρόθεμα \u. Η τιμή που ακολουθεί το \u διαβάζεται στο δεκαεξαδικό σύστημα και η σωστή ορθογραφία επιβάλλει να αναγράφονται και τα 4 ψηφία (εξού και τα μηδενικά στην αρχή).



1.4 Μαθηματικές πράξεις με χαρακτήρες
Εδώ ξεδιπλώνεται όλη η μαγεία της κωδικοποίησης. Η Java μας δίνει τη δυνατότητα να κάνουμε πράξεις με μεταβλητές τύπου char, όπως ακριβώς θα κάναμε με ένα ακέραιο τύπο δεδομένων.

Για παράδειγμα:
Μορφοποιημένος Κώδικας: Επιλογή όλων
char ch = 'a';
System.out.println(ch);

ch++;
System.out.println(ch);


Ας αναλογιστούμε για λίγο τι κάνει ο παραπάνω κώδικας: δημιουργεί ένα char με τιμή 0x0061 (='a') και το τυπώνει στην οθόνη.
Ύστερα εκτελεί την εντολή ch++, και το ch γίνεται 0x0062 (='b'). Σαν αποτέλεσμα θα τυπωθεί στην οθόνη το a και το b!

Μπορούμε φυσικά να χρησιμοποιήσουμε όλους τους γνωστούς τελεστές ++ -- + - * / κτλ... όλοι αυτοί θα δράσουν στην τιμή του χρακτήρα βλέποντάς την σαν ακέραιο αριθμό.
Υπάρχει όμως ένα λεπτό σημείο που πρέπει να προσέξουμε:
Μορφοποιημένος Κώδικας: Επιλογή όλων
char ch = 'a';
ch = ch+2;


Ο παραπάνω κώδικας θα «νευριάσει» τον compiler επειδή η πράξη ch+2 επιστρέφει έναν int, και όχι char. Για να είμαστε λοιπόν απόλυτα σωστοί θα πρέπει να γράψουμε
Μορφοποιημένος Κώδικας: Επιλογή όλων
char ch = 'a';
ch = (char) (ch+2); //Τώρα το ch έγινε 'c'!


Φυσικά ο τύπος char μπορεί να συμμετάσχει και σε συγκρίσεις όπως με τους τελεστές == > < κτλ. Έτσι μη διστάσετε να ελέγξετε αν ο χαρακτήρας ch είναι «μικρότερος από 180», ή «ίσος με 0x20»...

Μπορούμε επίσης να χρησιμοποιούμε όσο συχνά θέλουμε το type casting. Για παράδειγμα όλα τα ακόλουθα είναι σωστά:
Μορφοποιημένος Κώδικας: Επιλογή όλων
int i=97;	//'a'
long l=98; //'b'
short s=99; //'c'
byte b=100; //'d'

System.out.print( (char)i );
System.out.print( (char)l );
System.out.print( (char)s );
System.out.print( (char)b );
System.out.print( (char)101 );
Αν δεν μετατρέπαμε τα δεδομένα μας σε char, θα βλέπαμε στην οθόνη τις τιμές 97, 98 ... 101.
Τώρα όμως τα δεδομένα μετατρέπονται σε char, και στην οθόνη τυπώνεται το "abcde", δηλαδή οι χαρακτήρες υπ' αριθμόν 97, 98 ... 101, σύμφωνα με τη σύμβαση UTF-16.


Νά και ένα χρήσιμο πρόγραμμα:
Μορφοποιημένος Κώδικας: Επιλογή όλων
//αρχείο CharTest.java
public class CharTest {

public static void main(String arg[]) {
java.util.Scanner sc = new java.util.Scanner(System.in);
char ch=0;
String str="";

System.out.print("Πιέστε σκέτο Enter για τον επόμενο χαρακτήρα, δώστε p για τον προηγούμενο και q για έξοδο\n\n");

for (;;) {
System.out.print("Δεκαδικό= "+(int)ch+"\t\tΧαρακτήρας= "+ch+"\t");
str=sc.nextLine();

if (str.equals("")) ch++;
else if (str.equals("p")) ch--;
else if (str.equals("q")) break;
} //for
} //main

}

Πατήστε πολλές φορές Enter και θα δείτε όλους τους χαρακτήρες UTF-16 να περνούν από μπροστά σας. Θα δείτε «περίεργα πράγματα» να συμβαίνουν πριν το 33, όπως τον κέρσορα να αλλάζει παραγράφους, να σβήνει χαρακτήρες κτλ. Είναι οι μη-εκτυπώσιμοι, ειδικοί χαρακτήρες που λέγαμε πιο πριν.



2. Συμβολοσειρές - String
Όπως έχετε ήδη καταλάβει, ένα String είναι μία σειρά από char. Όλοι οι char έχουν μήκος 2 byte, άρα ένα String πιάνει χώρο στη μνήμη 2*μήκος σε χαρακτήρες.
Το String είναι ένα αντικείμενο της κλασης String. Από τη στιγμή που δημιουργείται δεν αλλάζει. Αν θέλουμε να το αλλάξουμε δημιουργούμε ένα καινούριο String, και βάζουμε τη μεταβλητή μας να «δείχνει» στο νέο αντικείμενο. Πχ:
Μορφοποιημένος Κώδικας: Επιλογή όλων
String str = "Γειά σου";
//...
//...
//...
str = "Τι κάνεις;"; //αυτή η εντολή φτιάχνει ένα καινούριο String, δεν αλλάζει το αρχικό...


Αν θέλουμε να συγκρίνουμε αν δύο String είναι ίδια ή όχι, χρησιμοποιούμε την μέθοδο equals, και ΟΧΙ τον τελεστή ==, όπως έχουμε ήδη ξεκαθαρίσει στο κεφάλαιο με τα αντικείμενα. Ο τελεστής == συγκρίνει pointers, όχι αντικείμενα!




2.1 Μέθοδοι της Κλάσης String
Για τις μεθόδους της κλάσης αυτής μιλήσαμε και στο κεφάλαιο 9. Εδώ θα παραθέσω και πάλι λίγες από αυτές, καθώς και ένα μικρό πρόγραμμα που δείχνει τη χρήση τους.


String( char[] ch ): Constructor που δημιουργεί ένα String, βάζοντας στη σειρά τα στοιχεία του πίνακα char[].
String( char[] ch, int offset, int count ): Ίδιο με το παραπάνω, μόνο που δεν χρησιμοποιεί όλο τον πίνακα ch. Χρησιμοποιεί μόνο "count" στοιχεία, αρχίζοντας από το στοιχείο offset+1.
String ( String s ): Απλώς δημιουργεί ένα νέο String που είναι αντίγραφο του ορίσματος s.

char charAt( int index ): Επιστρέφει τον χαρακτήρα στη θέση index.
char[] toCharArray(): Επιστρέφει το String με τη μορφή πίνακα char.

int indexOf( int ch ): Το ch παρ' όλο που είναι int, φανταστείτε πως αντιπροσωπεύει ένα char. Η μέθοδος αυτή επιστρέφει τη θέση στο String μας που συναντάμε για πρώτη φορά αυτόν τον χαρακτήρα. Επιστρέφει -1 αν δεν τον βρει καθόλου.
int lastIndexOf( int ch ): Ακριβώς όπως η indexOf, αλλά αρχίζει την αναζήτηση από το τέλος.
int length(): Επιστρέφει το μήκος του String σε χαρακτήρες.

boolean startsWith( String s ): Επιστρέφει true αν το String αρχίζει με το s.
boolean endsWith( String s ): Επιστρέφει true αν το String τελειώνει με το s.
boolean contains( String s ): Ελέγχει αν το String που κάλεσε τη συνάρτηση «περιέχει» το όρισμα s. (Στην πραγματικότητα το όρισα της μεθόδου αυτής είναι CharSequence και όχι String. Αγνοήστε όμως αυτή τη λεπτομέρεια μέχρι να μιλήσουμε για intefaces.
boolean isEmpty(): Επιστρέφει true αν το String μας είναι το "". Προσοχή! Όχι να είναι null, να έχει απλώς άδειο κείμενο.
boolean equals( Object ob ): Αυτή η μέθοδος μας έρχεται από την κλάση Object. Επιστρέφει true αν το όρισμά μας είναι ένα String, και περιέχει το ίδιο κείμενο με το String που κάλεσε τη μέθοδο.

String replace( char oldchar, char newchar ): Αντικαθιστά με newchar, όλους τους χαρακτήρες που είναι ίσοι με oldchar.
String toUpperCase(): Επιστρέφει ένα νέο String παίρνοντας το παλιό και κάνοντας όλα τα γράμματά του κεφαλαία.
String toLowerCase(): Ομοίως, μόνο που κάνει όλα τα γράμματα πεζά.

String[] split(String regex): Επιστρέφει ένα πίνακα από τα κομμάτια του αρχικού String. Τα κομμάτια τέμνονται όπου η μέθοδος συναντήσει το όρισμα regex.

Και το προγραμματάκι που ξεκαθαρίζει πως δουλεύουν τα παραπάνω:
Μορφοποιημένος Κώδικας: Επιλογή όλων
//αρχείο StringMethods.java
public class StringMethods {

public static void main(String args[]) {

String inp="";
java.util.Scanner sc = new java.util.Scanner(System.in);

System.out.print("\nΔώστε ένα κείμενo, ή q για να τερματίσετε το πράγραμμα.");

for (;;) {

System.out.print("\n>");
inp = sc.nextLine();
if (inp.equals("q")) System.exit(0);

try { System.out.print("\tinp.charAt(5)= "+inp.charAt(5)+"\n"); }
catch (Exception ex) { System.out.print("\tinp.charAt(5)= δεν υπάρχει\n"); }

System.out.print("\tinp.indexOf('φ')= "+inp.indexOf('φ')+"\n");
System.out.print("\tinp.lastIndexOf('φ')= "+inp.lastIndexOf('φ')+"\n");
System.out.print("\tinp.length()= "+inp.length()+"\n");
System.out.print("\tinp.startsWith(\"προ\")= "+inp.startsWith("προ")+"\n");
System.out.print("\tinp.endsWith(\"ος\")= "+inp.endsWith("ός")+"\n");
System.out.print("\tinp.contains(\"γρ\")= "+inp.contains("γρ")+"\n");
System.out.print("\tinp.isEmpty()= "+inp.isEmpty()+"\n");
System.out.print("\tinp.equals(\"πρόγραμμα Java\")= "+inp.equals("πρόγραμμα Java")+"\n");
System.out.print("\tinp.replace('ν', 'Δ')= "+inp.replace('ν','Δ')+"\n");
System.out.print("\tinp.toUpperCase()= "+inp.toUpperCase()+"\n");
System.out.print("\tinp.toLowerCase()= "+inp.toLowerCase()+"\n");
} //for
} //main

}




2.2 Μετατροπή βασικών τύπων σε String και αντίστροφα
Μία πολύ βασική απαίτηση που έχουμε από τα κείμενα που παίρνουμε από το χρήστη είναι να μπορούν να μετατραπούν σε βασικούς τύπους (int, float, long κτλ). Ομοίως για τους βασικούς τύπους έχουμε την απαίτηση να μπορούν να μετατραπούν σε κείμενο για να τους τυπώσουμε στην οθόνη, ή για κάποιο άλλο σκοπό. Η Java μας δίνει πολλά εργαλεία για αυτό το σκοπό.

Ας αρχίσουμε από το πιο εύκολο: πως να μετατρέπουμε ένα βασικό τύπο σε String. Υπάρχουν δύο τρόποι, ο προφανής και ο πονηρός.

Ο προφανής είναι να χρησιμοποιήσουμε τις static μεθόδους valueOf της κλάσης String. Αυτές οι μέθοδοι παίρνουν σαν όρισμα ένα βασικό τύπο, και επιστρέφουν ένα κείμενο που περιγράφει την τιμή του σε «ανθρώπινη» γλώσσα (γιατί η απ' ευθείας την τιμή των τύπων είναι βέβαια μία σειρά από 0 και 1).

Για παράδειγμα:
Μορφοποιημένος Κώδικας: Επιλογή όλων
int i=98000;
long l= 987745356759L;
char ch='k';
boolean b=false;
float f=3.14159;
double d=2.718281828;

String str1 = String.valueOf(l);
String str2 = String.valueOf(i);
//ή και απ ευθείας χρήση, πχ:
System.out.print( String.valueOf(b) );

Αν θέλουμε να μετατρέψουμε short ή byte σε κείμενο, απλώς τους μετατρέπουμε σε int με type casting και κάνουμε τη δουλειά μας...


Ας δούμε όμως και τον πονηρό τρόπο :-) Γράφουμε απλώς την τιμή ή τη μεταβλητή του βασικού τύπου, και ύστερα «προσθέτουμε» το "", δηλαδή ένα κενό String (ή τέλος πάντων ένα οποιοδήποτε String). Κάπως έτσι:
Μορφοποιημένος Κώδικας: Επιλογή όλων
int i=98000;
String str1 = i+""; //αυτό ήταν!

//ή
long l=987745356759L;
String str2 = l+"\n";


Περνάμε τώρα στην μετατροπή κειμένου σε βασικούς τύπους.
Εδώ τα πράγματα είναι πιο δύσκολα, και θα μπορούμε να κάνουμε μία «σοβαρή δουλειά» μόνο μετά το τέλος του επομένου κεφαλαίου.

Ο λόγος είναι βασικά ότι ενώ οι βασικοί τύποι μπορούν να μετατραπούν πάντα σε κείμενο, το αντίθετο δε συμβαίνει.
Για παράδειγμα θέλουμε να διαβάσουμε ένα κείμενο από το χρήστη και να το μετατρέψουμε σε σε ακέραιο αριθμό. Έστω λοιπόν ότι ο χρήστης μας δίνει το κείμενο "234β" για κάποιο λόγο. Αν πάμε να μετατρέψουμε το κείμενο αυτό σε αριθμό το πρόγραμμα θα κρασάρει για λόγους που όλοι μας καταλαβαίνουμε.

Παρ όλα αυτά, ελπίζοντας πως το κείμενο που θα μετατρέψουμε θα είναι έγκυρο, έχουμε δύο τρόπους για να το αντιμετωπίσουμε:
1. Χρησιμοποιούμε τις static μεθόδους Integer.parseInt( String text ), Float.parseFloat( String text ), Boolean.parseBoolean( String text ) κτλ με όρισμα το κείμενο που περιέχει την πληροφορία που θέλουμε.
2. Δημιουργούμε ένα κατάλληλο αντικείμενο (πχ Scanner sc = new Scanner(text) με όρισμα το String) και διαβάζουμε τον τύπο με τις μεθόδους nextInt(), nextFloat() κτλ του Scanner, ή κάποιες αντίστοιχες αν δημιουργήσαμε άλλο αντικείμενο αντί για Scanner.

Η πρώτη περίπτωση θέλει ιδιαίτερη προσοχή γιατί το κείμενο πρέπει να είναι σκέτο. Δεν μπορεί να γράψουμε:
Μορφοποιημένος Κώδικας: Επιλογή όλων
int i= Integer.parseInt( "ο αριθμός είναι 98000");
Γιατί το πρόγραμμα θα τερματίσει.

Το σωστό είναι σκέτο:
Μορφοποιημένος Κώδικας: Επιλογή όλων
int i= Integer.parseInt( "98000");



3. Κωδικοποιήσεις χαρακτήρων; Μην ανησυχείτε!
Ίσως στους διορατικούς αναγνώστες να δημιουργήθηκε η εξής απορία: «Η Java δουλεύει σε UTF-16. Το σύστημά μου όμως δουλεύει σε UTF-8 ή σε WINDOWS-1252 κτλ. Τι γίνεται όταν αυτά τα δύο πάνε να συνεργαστούν; Όταν πχ. τυπώνω χαρακτήρες στην οθόνη, όταν γράφω ή διαβάζω αρχεία από το σκληρό μου δίσκο; Δεν θα προκληθεί χάος;»

Η απάντηση (ευτυχώς) είναι ότι τέτοια πράγματα δεν πρέπει να μας ανησυχούν καθόλου!
Ας μην ξεχνάμε την ουσία της Java: το Virual Machine. Εμείς γράφουμε ένα bytecode. Το Virtual Machine που είναι εγκατεστημένο στον κάθε υπολογιστή παίρνει το bytecode μας και το διαβάζει όπως αυτό νομίζει. Αυτός είναι και ο λόγος που κάνουμε compile «εδώ», όμως το πρόγραμμά μας εκτελείται σωστά και «εκεί».

Κάθε φορά λοιπόν που πάμε να κάνουμε βασικές διαδικασίες όπως τύπωμα χαρακτήρων στην οθόνη, διάβασμα ή γράψιμο σε αρχεία, το Virtual Machine έχει φροντίσει να φτιάξει τα κατάλληλα αντικείμενα με τον κατάληλο τρόπο. Για παράδειγμα το System.out από το οποίο τυπώνουμε είναι ένα αντικείμενο PrintStream. Το Virtual Machine φτιάχνει τα αντικείμενα PrintStream με τέτοιο τρόπο ώστε να μετατρέπουν αυτόματα τους UTF-16 χαρακτήρες σε UTF-8 (ή σε οτιδήποτε άλλο θέλει το σύστημα). Έτσι οι χαρακτήρες εμφανίζονται κανονικά στην οθόνη. Το ίδιο γίνεται για αντικείμενα όπως το Scanner, PrintWriter και άλλα που χρησιμοποιούνται πχ. για να γράφουν ή να διαβάζουν αρχεία του σκληρού μας δίσκου.

Αν εμείς παρ' όλα αυτά επιμένουμε (για τους λόγους μας) να γράψουμε ή να διαβάσουμε με μία συγκεκριμένη κωδικοποίηση χαρακτήρων, διαφορετική από την προεπιλεγμένη του εκάστοτε συστήματος, μπορούμε. Τέτοιες εργασίες όμως πολύ σπάνια έχουν νόημα και γι αυτό είναι εκτός της εμβέλειας αυτού του οδηγού. Οι ενδιαφερόμενοι ας ανατρέξουν στην κλάση Charset.

Επιπλέον, προγράμματα όπως ο gedit στο linux, το LibreOffice ή άλλα παρόμοια, ξέρουν να αναγνωρίζουν πολλές άλλες κωδικοποιήσεις εκτός από την «δική τους». Ακόμα λοιπόν και αν γράφαμε σε UTF-16 ή κάτι άλλο, δε θα υπήρχε τόσο μεγάλο πρόβλημα...

Προηγούμενο: Exceptions
Επόμενο: Αρχεία

Creative Commons License
Η εργασία υπάγεται στην άδεια Creative Commons Αναφορά-Παρόμοια διανομή 3.0 Ελλάδα
Τελευταία επεξεργασία από alkismavridis και 22 Απρ 2014, 20:12, έχει επεξεργασθεί 5 φορά/ες συνολικά
Γνώσεις ⇛ Linux: Μέτριο┃ Προγραμματισμός: Java, Assembly, Fortran, μαθαίνω C/X11┃ Αγγλικά: Μέτρια
Λειτουργικό σε Η/Υ ϰ μοντέλο: Ubuntu 14.04 64-bit ┃ Τρόπος εγκατάστασης: Live USB
Προδιαγραφές ⇛ Desktop: Intel i5 2320 3.00GHz.┃ MotherBoard: Asus p8h61 -m pro
Προδιαγραφές ⇛ RAM: 4GB ┃ Τροφοδοτικό Corsair CX430

GPU: Intel 2nd Generation Core Processor Family Integrated Graphics Controller [8086:0102] {i915}
5 eth0: Realtek RTL8111/8168B PCI Express Gigabit Ethernet controller [10ec:8168] (rev 06) ⋮ wlan0: 0b05:1723 ASUS WL-167G v2 802.11g Adapter [Ralink RT2571W]
Οθόνη Schaub Lorenz (Tv)
alkismavridis
punkTUX
punkTUX
 
Δημοσιεύσεις: 273
Εγγραφή: 18 Μαρ 2009, 18:46
Εκτύπωση

Re: Εισαγωγή στην Java - κεφ. 11

Δημοσίευσηαπό alkismavridis » 21 Νοέμ 2013, 19:37

Άλλαξα τη σειρά των κεφαλαίων 10 και 11...
Γνώσεις ⇛ Linux: Μέτριο┃ Προγραμματισμός: Java, Assembly, Fortran, μαθαίνω C/X11┃ Αγγλικά: Μέτρια
Λειτουργικό σε Η/Υ ϰ μοντέλο: Ubuntu 14.04 64-bit ┃ Τρόπος εγκατάστασης: Live USB
Προδιαγραφές ⇛ Desktop: Intel i5 2320 3.00GHz.┃ MotherBoard: Asus p8h61 -m pro
Προδιαγραφές ⇛ RAM: 4GB ┃ Τροφοδοτικό Corsair CX430

GPU: Intel 2nd Generation Core Processor Family Integrated Graphics Controller [8086:0102] {i915}
5 eth0: Realtek RTL8111/8168B PCI Express Gigabit Ethernet controller [10ec:8168] (rev 06) ⋮ wlan0: 0b05:1723 ASUS WL-167G v2 802.11g Adapter [Ralink RT2571W]
Οθόνη Schaub Lorenz (Tv)
alkismavridis
punkTUX
punkTUX
 
Δημοσιεύσεις: 273
Εγγραφή: 18 Μαρ 2009, 18:46
Εκτύπωση

Re: Εισαγωγή στην Java - κεφ. 11

Δημοσίευσηαπό simosx » 21 Νοέμ 2013, 21:02

alkismavridis έγραψε:Τίθεται λοιπόν η ερώτηση πως αυτά τα δύο συνδέονται. Δηλαδή ποια σειρά από 0 και 1 αντιστοιχεί σε ποιον χαρακτήρα; Και ποιος το καθορίζει αυτό;

Η απάντηση ίσως σας απογοητεύσει. Ακόμα δεν υπάρχει μία καθολική συμφωνία ότι «αυτή η σειρά 0 και 1 αντιστοιχεί σε αυτόν τον χαρακτήρα». Ίσως και να μην υπάρξει ποτέ!
Αντίθετα υπάρχουν πολλοί τέτοιοι «χάρτες» που κάνουν την αντιστοίχηση και ονομάζονται κωδικοποιήσεις χαρακτήρων.

το linux, οι περισσότεροι ιστότοποι, και τα λογισμικά της Apple χρησιμοποιούν μία κωδικοποίηση με όνομα UTF-8.
Η Microsoft έχει τις δικές της κωδικοποιήσεις χαρακτήρων, αγνοώντας (ως συνήθως) όλο τον υπόλοιπο κόσμο. H πιο πρόσφατη (γράφω στις 15-11-2013) ονομάζεται WINDOWS-1252.


Το Windows-1253, το iso-8859-7, το CP737 είναι κωδικοποιήσεις χαρακτήρων που εμφανίστηκαν στη δεκαετία του '80 και '90.
Πρόκειται για κωδικοποιήσεις των 8-bit, με αποτέλεσμα να μπορούν να απεικονίσουν μέχρι 256 διαφορετικούς χαρακτήρες.
Όλα αυτά είναι τώρα παρωχημένα, και τώρα έχουμε το πρότυπο Unicode, http://www.unicode.org/ όπου κάθε χαρακτήρας έχει και ένα μοναδικό αριθμό αναφοράς.
Αν τρέξουμε gucharmap (Πίνακας χαρακτήρων), μπορούμε να δούμε τους χαρακτήρες του προτύπου Unicode με εύκολο τρόπο.
Εικόνα

1. Πάνω δεξιά λέει Ubuntu, που είναι η τρέχουσα γραμματοσειρά. Όταν είναι να δείξει χαρακτήρες, τότε το πρόγραμμα θα τους δείξει με την επιλεγμένη γραμματοσειρά. Με αυτό το τρόπο μπορούμε να δούμε πως δείχνει τους χαρακτήρες μια συγκεκριμένη γραμματοσειρά.

2. Αμέσως κάτω από τη γραμματοσειρά, αναφέρει Script (Γραφή), που ουσιαστικά είναι οι χαρακτήρες Unicode σε ομάδας που βγάζουν νόημα. Για παράδειγμα, στην ομάδα Greek έχει το μονοτονικό και το πολυτονικό. Στο πρότυπο εμφανίζονται σε διαφορετικές περιοχές.

3. Για τον ελληνικό χαρακτήρα Α, ο μοναδικός αριθμός του κατά το πρότυπο Unicode είναι το U+0391, που έχει την αριθμητική τιμή 0x0391 (είναι σε δεκαεξαδική μορφή).

Εικόνα

Εδώ είμαστε στις Λεπτομέρειες χαρακτήρα. Το ελληνικό αλφάβητο μπήκε στο πρότυπο Unicode από την αρχή, κάπου στα μέσα του '90.
Στο πρότυπο Unicode υπάρχουν κατηγοριοποιήσεις για κάθε χαρακτήρα, οπότε όταν προγραμματίζουμε, μπορούμε να ελέγχουμε αν ένας χαρακτήρας Unicode είναι αλφαβητικός, πεζό/κεφαλαίο, κ.α.

Αυτό το 0χ0391 είναι 931 στη δεκαδική μορφή. Οι υπόλοιποι ελληνική χαρακτήρες για το μονοτονικό είναι γύρω εκεί, μεταξύ 930-980.
Του πολυτονικού είναι κάπου μεταξύ 7930-8200.

Για τη χρήση του Unicode, χρειαζόμαστε κωδικοποιήσεις. Η πιο γνωστή είναι το UTF-8, που είναι μια πολύ έξυπνη κωδικοποίηση μεταβλητού μεγέθους.
Δηλαδή, το abcd είναι 4 χαρακτήρες, που σε UTF-8 καταλαμβάνουν 4 byte μόνο. Ενώ, τα ελληνικά (μονοτονικό) που γράφουμε είναι 2 byte για κάθε χαρακτήρα. Εργασία: πόσα byte είναι το «ένα μήλο»; Είναι 15 byte. Διότι έχουμε 7 χαρακτήρες μονοτονικού (7*2=14), και τον χαρακτήρα του διαστήματος που καταλαμβάνει 1 byte. Έχει ενδιαφέρον να διαβάσει κανείς το άρθρο για το πως δουλεύει το UTF-8. Ήταν μια πολύ έξυπνη λύση σε ένα περίπλοκο πρόβλημα.

Στο παραπάνω στιγμιότυπο μπορούμε να δούμε πως αποθηκεύεται εσωτερικά ένας χαρακτήρας Unicode σε κωδικοποίηση UTF-8 και σε UTF-16.
Είναι σημαντικό να πούμε ότι και το UTF-16 είναι κωδικοποίηση μεταβλητού μεγέθους, διότι υπάρχουν περισσότεροι από 65535 χαρακτήρες στο πρότυπο. Για παράδειγμα, ο χαρακτήρας [010 000]* (θα δείτε ένα κουτάκι με τα νούμερα 010 000 αν δεν έχετε γραμματοσειρά που να έχει και Γραμμική Β), καταλαμβάνει 4 byte σε UTF-8 και 4 byte σε UTF-16.

Αν έχετε διαβάσει ότι το UTF-16 καταλαμβάνει μόνο 2 byte, πρέπει να είναι από παλιά βιβλία όπου είχαν μάλλον στο μυαλό τους την παλιά κωδικοποίηση UCS-2.

Γενικά όλα τα παραπάνω δε θα τα δει κανείς σε προγραμματισμό, εκτός και αν έχει να έρθει σε επαφή με κείμενα σε παλιές κωδικοποιήσεις.

* το φόρουμ δεν υποστηρίζει χαρακτήρες Unicode από το Plane 1, οπότε δεν μπορώ να γράψω εκείνο τον χαρακτήρα.
προσωπικό ιστολόγιο ϗ πλανήτης Ubuntu-gr
Συμβάλετε και εσείς στο ελληνικό βιβλίο Ubuntu!
1 Γνώσεις Linux: Πολύ καλό ┃ Προγραμματισμού: Πολύ καλό ┃ Αγγλικών: Πολύ καλό
2 Ubuntu 13.10 saucy 3.11.0-031100rc1-generic 64bit (el_GR.UTF-8, Unity ubuntu)
3 AMD E-450 APU with Radeon HD Graphics ‖ RAM 3555 MiB ‖ Sony Corporation VAIO
4 AMD nee ATI Wrestler [Radeon HD 6320] [1002:9806] {fglrx_pci}
5 eth0: Atheros Inc. AR8151 v2.0 Gigabit Ethernet [1969:1083] (rev c0) ⋮ wlan0: Atheros Inc. AR9285 [168c:002b] (rev 01)
Φτιάξτε και εσείς τη δική σας υπογραφή (παραπάνω κείμενο) αυτόματα με κλικ εδώ!
simosx
Επίτιμο μέλος
Επίτιμο μέλος
 
Δημοσιεύσεις: 10334
Εγγραφή: 11 Μάιος 2008, 18:52
Launchpad: simosx
IRC: simosx
Εκτύπωση

Re: Εισαγωγή στην Java - κεφ. 11

Δημοσίευσηαπό lucinos » 21 Νοέμ 2013, 21:49

θυμήθηκα αυτό που είχα γράψει εδώ: http://forum.ubuntu-gr.org/viewtopic.php?f=9&t=21330

για την ιστορία το utf-16 είναι μεταβλητού μήκους κωδικοποίηση και άλλοι χαρακτήρες (οι συχνοί) πιάνουν 16bit και άλλοι 32bit (οι σπάνιοι). Το 16 σημαίνει μάλλον ότι χωρίζεται ο κώδικας σε κομμάτια τών 16bit.
και το utf-8 είναι μεταβλητού μήκους.
Spoiler: show
Γνώσεις → Linux: Μέτριος ┃ Προγραμματισμός: Μέτριος ┃ Αγγλικά: Μέτριος
Λειτουργικό → Ubuntu 11.04 natty 64-bit (el_GR.UTF-8)
Προδιαγραφές → CPU: 4x Intel Core i5 CPU 750 2.67GHz ‖ RAM 3953 MiB ‖ ASRock P55DE3
Κάρτες γραφικών: nVidia G92 [GeForce GTS 250] ⎨10de:0615⎬ (rev a2)
Δίκτυα: eth0: Realtek RTL8111/8168B PCI Express Gigabit Ethernet controller ⎨10ec:8168⎬ (rev 03)
Άβαταρ μέλους
lucinos
daemonTUX
daemonTUX
 
Δημοσιεύσεις: 828
Εγγραφή: 12 Δεκ 2010, 22:04
Εκτύπωση

Re: Εισαγωγή στην Java - κεφ. 11

Δημοσίευσηαπό g1wrg0s » 05 Απρ 2014, 17:41

Να ρωτησω κατι σχετικα με αναγνωση κειμενου.

1. Οταν διαβαζω με RandomAccessReader εχω θεματα με ορισμενους χαρακτηρες ενω οταν διαβαζω με BufferedReader οχι, γιατι να συμβαινει εφοσον και τα 2 σε utf8 διαβαζουν

2. Πως γινεται να παρω τη θεσηστην οποια εγραψα μεσα σε ενα αρχειο;
Spoiler: show
1 Γνώσεις Linux: Πρώτα βήματα ┃ Προγραμματισμού: Πρώτα βήματα ┃ Αγγλικών: Πρώτα βήματα
2 Ubuntu 12.10 quantal 3.10.20-031020-generic 32bit (el_GR.UTF-8, Unity ubuntu), Windows 8
3 Intel Core i5-3230M CPU @ 2.60GHz ‖ RAM 7923 MiB ‖ Acer VA50_HC_CR - Acer Aspire V3-571G
4 Intel 3rd Gen Core processor Graphics Controller [8086:0166] {i915} ⋮ nVidia Device [10de:0fe1] {}
5 eth0: Broadcom NetLink BCM57785 Gigabit Ethernet PCIe [14e4:16b5] (rev 10) ⋮ wlan0: Atheros Inc. AR9462 Wireless Network Adapter [168c:0034] (rev 01)
g1wrg0s
punkTUX
punkTUX
 
Δημοσιεύσεις: 196
Εγγραφή: 26 Μάιος 2012, 10:29
Εκτύπωση

Re: Εισαγωγή στην Java - κεφ. 11

Δημοσίευσηαπό alkismavridis » 22 Απρ 2014, 02:31

g1wrg0s, τι ακριβώς εννοείς «θεση στην οποια εγραψα μεσα σε ενα αρχειο»;

( βασικά το επόμενο κεφάλαιο που είναι σχεδόν έτοιμο και θα δημοσιευθεί σύντομα αφορά τα αρχεία, οπότε ίσως να σε καλύψει...)
Γνώσεις ⇛ Linux: Μέτριο┃ Προγραμματισμός: Java, Assembly, Fortran, μαθαίνω C/X11┃ Αγγλικά: Μέτρια
Λειτουργικό σε Η/Υ ϰ μοντέλο: Ubuntu 14.04 64-bit ┃ Τρόπος εγκατάστασης: Live USB
Προδιαγραφές ⇛ Desktop: Intel i5 2320 3.00GHz.┃ MotherBoard: Asus p8h61 -m pro
Προδιαγραφές ⇛ RAM: 4GB ┃ Τροφοδοτικό Corsair CX430

GPU: Intel 2nd Generation Core Processor Family Integrated Graphics Controller [8086:0102] {i915}
5 eth0: Realtek RTL8111/8168B PCI Express Gigabit Ethernet controller [10ec:8168] (rev 06) ⋮ wlan0: 0b05:1723 ASUS WL-167G v2 802.11g Adapter [Ralink RT2571W]
Οθόνη Schaub Lorenz (Tv)
alkismavridis
punkTUX
punkTUX
 
Δημοσιεύσεις: 273
Εγγραφή: 18 Μαρ 2009, 18:46
Εκτύπωση


  • ΣΧΕΤΙΚΑ ΘΕΜΑΤΑ
    ΑΠΑΝΤΗΣΕΙΣ
    ΠΡΟΒΟΛΕΣ
    ΣΥΓΓΡΑΦΕΑΣ

Επιστροφή στο Μαθήματα Java