Προς το περιεχόμενο

Java String.equals( (String)Object) - είναι byte comparison?


migf1

Προτεινόμενες αναρτήσεις

Θα μπορούσε κάποιος να επιβεβαιώσει/διαψεύσει αν η μέθοδος του τίτλου είναι σύγκριση bytes ή όχι; Επίσης είναι locale-aware ή όχι;

 

Φτιάχνω στην LIBS ένα απλοποιημένο Java-like API, προσαρμοσμένο σε απλά c-strings (δηλαδή NUL terminated arrays of char, όπου char το στάνταρ ASCII value, κι όχι το 16bit Unicode char της Java) και τα 'χω πάρει ολίγον με τα locale και μη locale-aware methods της Java. Άλλα είναι documented, άλλα ( όπως η equals() ) δεν είναι... ή τουλάχιστον δεν βρίσκω εγώ την σχετική τεκμηρίωση.

 

Δεν με βοηθάει ούτε ο πηγαίος της κώδικας (μάλλον επειδή δεν είμαι τόσο εξοικειωμένος με την Java)...

 

 

  998       /**
  999        * Compares this string to the specified object.  The result is {@code
 1000        * true} if and only if the argument is not {@code null} and is a {@code
 1001        * String} object that represents the same sequence of characters as this
 1002        * object.
 1003        *
 1004        * @param  anObject
 1005        *         The object to compare this {@code String} against
 1006        *
 1007        * @return  {@code true} if the given object represents a {@code String}
 1008        *          equivalent to this string, {@code false} otherwise
 1009        *
 1010        * @see  #compareTo(String)
 1011        * @see  #equalsIgnoreCase(String)
 1012        */
 1013       public boolean equals(Object anObject) {
 1014           if (this == anObject) {
 1015               return true;
 1016           }
 1017           if (anObject instanceof String) {
 1018               String anotherString = (String)anObject;
 1019               int n = count;
 1020               if (n == anotherString.count) {
 1021                   char v1[] = value;
 1022                   char v2[] = anotherString.value;
 1023                   int i = offset;
 1024                   int j = anotherString.offset;
 1025                   while (n-- != 0) {
 1026                       if (v1[i++] != v2[j++])
 1027                           return false;
 1028                   }
 1029                   return true;
 1030               }
 1031           }
 1032           return false;
 1033       }
 1034   

 

Και για να μην αλλάζω νήμα, αν θέλατε να φτιάξετε σε ANSI C μια συνάρτηση σύγκρισης 2 c-strings που δεν θα είναι locale-aware, και δεδομένου πως όλα τα C προγράμματα ξεκινάνε πάντα με ένα default locale (συνήθως "C") πως θα το κάνατε;

 

Υπάρχει κάποιος άλλος τρόπος πλην του να φτιάξουμε δικιά μας απεικόνιση των char;

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Απ τον κωδικα εγω βλεπω char-by-char συγρισεις, στη γραμμη 1026 δηλαδη. Με τον operator != στα primitive data types, συγκρινουμε bytes (νομιζω).

Oποτε η απαντηση ειναι ναι (χωρις να ειμαι 100% σιγουρος)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Το primitive char type στην Java δεν ορίζεται ως 16μπιτο Unicode16 entity? Διότι έτσι γνώριζα.

 

EDIT:

 

Αν είναι (που νομίζω είναι) τότε μας εγγυάται η equals() πως όντως είναι byte σύγκριση (απαλλαγμένη από endianess, surrogates, κλπ); Επίσης, με το locale γνωριζει κανείς τι παίζει για την συγκεκριμένη μέθοδο;

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ε ναι, αφού κάθε char έχει μια αριθμητική 16-bit τιμή 0 μέχρι ~65000 , αυτή συγκρίνει ανεξάρτητα από endianess και locale.

 

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Character.html#compareTo

 

Compares two Character objects numerically

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Για το locale δεν γινεται να το τσεκαρεις;

πχ να συγκρινεις δυο strings (με equals) τα οποια εχουν ιδια αναπαρασταση αλλα διαφοριτικο locale

(αν λεω λαλακια feel free να κραξετε)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

String equality και locales απλά δε συνδέονται.

 

Εφόσον μιλάμε για μια method equals (επιστρέφει true/false) και εφόσον το internal encoding στα strings της Java είναι συγκεκριμένο (δεν έχει σημασία ποιό είναι καν) δεν υπάρχει κανένας τρόπος με τον οποίο μια locale -- και συγκεκριμένα το collation -- θα μπορούσε να επηρρεάζει¹ το αποτέλεσμα της σύγκρισης. Αυτός είναι αρκετός λόγος για να μην υπάρχει πουθενά αναφορά στο τι γίνεται: does not apply.

 

Αν μιλούσαμε για μια method compare (επιστρέφει int) τότε ναι, το collation μπαίνει στη συζήτηση.

 

Update: ...και γι' αυτό το λόγο η String.compareTo αναφέρει σαφώς το τι είδους comparison κάνει.

 

Update #2: ...και ακριβώς από κάτω βλέπω την compareToIgnoreCase και σκέφτομαι αν είναι δυνατόν να είναι τόσο ανίκανοι και να έβαλαν μια method η οποία δε μπορεί παρά να λειτουργεί σωστά "συνήθως αλλά μη το δένεις και κόμπο". To their credit υπάρχει σχόλιο που λέει μη τη χρησιμοποιείς, έχουμε καλύτερα.

 

Ενδιαφέρουσα ερώτηση για όποιον θέλει να εμβαθύνει λίγο σε Unicode: για ποιό λόγο η compareToIgnoreCase  με το υπάρχον signature δεν μπορεί να εγγυηθεί ότι θα δουλέψει σωστά;

 

Hint#1

 

Το κακό ξεκινάει από το ότι δεν της λέμε ποιό locale να χρησιμοποιήσει για τη σύγκριση.

 

 

 

Hint#2

 

 

Και στην compareTo δεν το λέμε, όμως αυτή δεν έχει ανάλογο πρόβλημα (άσχετα που είναι "άχρηστη" για γενική χρήση, αυτό που κάνει το κάνει με συνέπεια). Άρα η διαφορά πρέπει να βρίσκεται σε κάτι που κάνει η μία διαφορετικά από την άλλη. Τί είναι αυτό;

 

 

 

 

 

 

 

¹ Θα μπορούσε βέβαια θεωρητικά να υπάρχει τρόπος να ελέγχεις το αν η σύγκριση θα γίνεται πάνω στα περιεχόμενα των strings ως έχουν ή πάνω σε normalized μορφές τους. Αυτό όμως πέραν του ότι είναι αμφιβόλου χρησιμότητας για να μπει στη "standard library" γενικά και εγκληματικό να ισχύει by default, επίσης δεν έχει να κάνει με locale.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ε ναι, αφού κάθε char έχει μια αριθμητική 16-bit τιμή 0 μέχρι ~65000 , αυτή συγκρίνει ανεξάρτητα από endianess και locale.

 

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Character.html#compareTo

 

Compares two Character objects numerically

Ok, thanks!

 

Οπότε σε C καλώς κάνω τη σύγκριση ως unsigned chars: http://x-karagiannis.gr/prg/custom/doc/libs/html/s2java_8c_source.html#l00272 απλώς πρέπει να συμπληρώσω στις διαφορές πως η LIBS εκδοχή είναι locale specific. Σωστά;

 

EDIT1:

 

Ώπα, έπεσαν πολλές απαντήσεις όσο έγραφα. Πάω ν αφάω όμως τώρα, και θα τις διαβάσω μετά (thanks).

 

EDIT2:

 

Έφαγα :)

 

@nilosgr & defacer:

 

Το πρόβλημα είναι πως στην C όλες οι αντίστοιχες ρουτίνες της libc είναι πάντα locale-aware. Για να μπορέσω να κάνω locale-independent συγκρίσεις, μετατροπές κλπ, πρέπει να φτιάξω custom απεικόνιση του τύπου char, και κατόπιν να αλλάξω σχεδόν τα πάντα στην βιβλιοθήκη (ζήσε Μάη μου δηλαδή, και δεν έχει και νόημα να μπω σε τέτοια διαδικασία για μια βιβλιοθήκη που υποστηρίζει μονάχα single-byte characters).

 

Οπότε, νομίζω θα αρκεστώ στο unsigned char comparison, κι απλώς θα γράψω στην τεκμηρίωση πως το simplified Java-like API της LIBS είναι πάντα locale-aware. Ήθελα όμως να διασταυρώσω πως η equals() είναι όντως byte σύγκριση (πάντως και τις compareTo(), contentsEqual() κλπ κλπ έτσι τις έχω κάνει, με unsigned char συγκρίσεις).

 

Ευχαριστώ όλους για τη συμμετοχή. Αν χρειαστώ κάτι άλλο θα επανέλθω,

  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Το πρόβλημα είναι πως στην C όλες οι αντίστοιχες ρουτίνες της libc είναι πάντα locale-aware. Για να μπορέσω να κάνω locale-independent συγκρίσεις, μετατροπές κλπ, πρέπει να φτιάξω custom απεικόνιση του τύπου char, και κατόπιν να αλλάξω σχεδόν τα πάντα στην βιβλιοθήκη (ζήσε Μάη μου δηλαδή, και δεν έχει και νόημα να μπω σε τέτοια διαδικασία για μια βιβλιοθήκη που υποστηρίζει μονάχα single-byte characters).

 

Πράγμα που συμβαίνει γιατί η C δεν έχει strings, έχει "μάτσα από characters" (δηλαδή το internal encoding δεν είναι συγκεκριμένο). Έχουμε ξανααναφερθεί σ' αυτό το θέμα (ICU vs standard library functions).

 

Οπότε, νομίζω θα αρκεστώ στο unsigned char comparison, κι απλώς θα γράψω στην τεκμηρίωση πως το simplified Java-like API της LIBS είναι πάντα locale-aware. Ήθελα όμως να διασταυρώσω πως η equals() είναι όντως byte σύγκριση (πάντως και τις compareTo(), contentsEqual() κλπ κλπ έτσι τις έχω κάνει, με unsigned char συγκρίσεις).

 

Το οποίο API σε τι μπορεί να διαφέρει από την ξερή strcmp?

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Το οποίο API σε τι μπορεί να διαφέρει από την ξερή strcmp?

Πέρα από ότι το simplified Java API παρέχει utility functions που δεν υπάρχουν στη στάνταρ <string.h> και ακόμα και για τις κοινές συχνά κάνει raise διαφορετικά errors (exceptions) και επίσης επιστρέφει και διαφορετικά πράγματα, όλη η LIBS αντί να κρασάρει στο bad-input κάνει raise errors, τα οποία μπορείς είτε να τα κάνεις catch είτε να τα αγνοήσεις. Επίσης, σου δίνει την δυνατότητα να επιλέξεις αν θα έχεις loud ή silent failures (by default είναι loud), καθώς επίσης αν θέλεις να γίνεται pause ή όχι το πρόγραμμά σου όταν προκαλεί σφάλματα (link1, link2)

 

Πέρα από το Java-like API, περιέχει ήδη μαζεμένες τις πιο συχνά χρησιμοποιούμενες c-string συναρτήσεις σε Unix & Unix-like πλατφόρμες (POSIX και μη), προσαρμοσμένες κι αυτές σε πιο αυστηρούς ελέγχους από ότι οι original + το error handling που περιγράφω στην προηγούμενη παράγραφο. Παρέχει και μερικές που στην original μορφή τους δεν είναι διαθέσιμες παντού, δλδ κάποια extensions κυρίως GNU και BSD (π.χ. την s_stresep() εγώ την έχω συνατήσει μονάχα σε NetBSD και Minix, η s_strnstr() είναι FreeBSD specific, η s_strnlen() είναι GNU specific, και πάει λέγοντας).

 

Ομοίως και για τις στάνταρ c-string συναρτήσεις (http://x-karagiannis.gr/prg/custom/doc/libs/html/group__libs_modified.html) και για κάποιες LIBS specific (http://x-karagiannis.gr/prg/custom/doc/libs/html/group__libs_util_funcs.html).

 

Στις στάνταρ και στις Unix-like μια σημαντική προσθήκη της LIBS είναι επίσης πως επιτρέπει overlapping strings (π.χ. η s_strcat()), τα οποία τα κάνει detect μόνη της κι αν επικαλύπτονται κάνει malloc temporary buffer internally, καθώς επίσης πως σε κάποιες συναρτήσεις π.χ. για tokenization παρέχει ειδικό όρισμα για το αν θέλουμε ή όχι να διατηρηθεί το αρχικό c-string ή όχι.

 

Είναι περισσότερο οργανωμένη συλλογή συναρτήσεων με κοινό πλαίσιο παρά βιβλιοθήκη. Αρχικά ήθελα αντί για Java-like API να της βάλω PHP-like API (μιλώντας πάντα για απλά c-strings) αλλά τελικά αποφάσισα να κάνω το 1ο, γιατί πιο clean.

 

Όταν τελειώσω με τις Java-like, μπορεί να βάλω και κάποιες PHP-like (π.χ. έχω φτιάξει ήδη explode(), με κάτι μικροδιαφορές προς το παρόν, όπως για παράδειγμα αν θα γίνεται ή όχι preserve το orgiginal string) και ίσως προσθέσω και από C++ ή και από C#, ανάλογα τα κέφια.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...