2017-07-17 3 views
0

J'essaie d'imiter la fonction de chaîne Rubby .bytesize en Python. Cependant, j'ai un problème avec certains caractères, par exemple. « « »Différents encodage en python et ruby ​​

Dans Ruby

"‘".bytesize returns 3 
"‘".bytes returns [226, 128, 152] 

En Python

ord("‘") returns 8216 
len(ord("‘")) returns 1 

Quelle est la différence dans le codage entre les deux langues? Ceci est encore plus confondu avec différents convertisseurs en ligne fournissant des résultats également contrastés. Par exemple - http://www.unit-conversion.info/texttools/ascii/ produit les mêmes résultats que Ruby, tandis que https://www.branah.com/ascii-converter produit les mêmes résultats que Python.

Répondre

1

Vous avez affaire à la chaîne UTF-8, oubliez les octets.

String#codepoints retournera le tableau codepoints, String#length renvoie la longueur de la chaîne UTF-8:

"‘".codepoints #⇒ [8216] 
"‘".length  #⇒ 1 

String#unpack fournit l'accès de bas niveau aux graphemas.

"‘".unpack "U+" 

Si vous voulez toujours obtenir un accès à octets, vous pourriez:

"‘".unpack "C*" 
#⇒ [226, 128, 152] 

Pour obtenir octets pour le symbole UTF-8 en python, on peut utiliser bytes:

>>> chars = bytes("‘".encode("utf8")) 
>>> chars 
#⇒ b'\xe2\x80\x98' 
>>> len(chars) 
#⇒ 3 
+0

donc, en Ruby quand "'" .bytes # => [226, 128, 152] quel est ce un retour ctually, quel encodage est-ce pour obtenir les octets pour? – slamham558

+0

Il obtient des octets pour le codage UTF-8 non codé sur un seul octet. – mudasobwa

+0

Comment est-ce que je pourrais répliquer cet effet en Python? Edit: nevermind vu votre édition la plus récente et cela fonctionne parfaitement, merci! – slamham558

0

Supposons que vous ayez deux UTF-8 chaînes en

Python 3:

>>> s1 
'è' 
>>> s2 
'è' 

et Ruby:

> s1 
=> "è" 
> s2 
=> "è" 

Alors que les cordes tous regardent les mêmes, ils ne sont pas:

>>> s1==s2 
False 

> s1==s2 
=> false 

C'est parce que pendant qu'il est le même grapheme ils sont en fait deux chaînes de caractères différents:Comme vous pouvez le voir, il existe plusieurs façons de créer un seul graphème, ou ce que nous appellerions des caractères.Si vous avez à composer des personnages, comme '̀' dans s2, la longueur de la chaîne, par octets, sera différent de celui que vous pourriez attendre:

> s1.length==s2.length 
=> false 

En Ruby, vous pouvez utiliser le \X regex pour rechercher les octets ou les groupes d'octets qui composent un seul graphème:

> s2.scan(/\X/) 
=> ["è"] 

ensuite leur longueur logique sera le même:

> s1.scan(/\X/).length==s2.scan(/\X/).length 
=> true 

Ou, normaliser la chaîne:

Vous pouvez également normalize la chaîne de s2 en Ruby pour combiner les deux octets en un seul équivalent graphème:

> s2.unicode_normalize.length==s1.length 
=> true 

En Python, vous recourraient soit unicodedate pour normaliser:

>>> import unicodedata 
>>> unicodedata.normalize('NFC', s2) == s1 
True 
>>> len(unicodedata.normalize('NFC', s2)) == len(s1) 
True 

Ou installez et utilisez le regex module qui prend en charge \X. (Le module re ne supporte pas \X)

Si ce que vous voulez vraiment dans la même approche octet par octet en Python comme Ruby, vous pouvez faire:

>>> [int(e) for e in bytes("‘".encode('utf-8'))] 
[226, 128, 152] 
> "‘".bytes 
=> [226, 128, 152] 

Mais je ne suis pas sûr de ce que vous l'intention de faire avec ça ...

Ou si vous voulez la même valeur ord:

>>> ord("‘") 
8216 
> "‘".ord 
=> 8216