Movatterモバイル変換


[0]ホーム

URL:


Navigation

Unicode HOWTO

Release:1.12

This HOWTO discusses Python support for Unicode, and explainsvarious problems that people commonly encounter when trying to workwith Unicode.

Introduction to Unicode

History of Character Codes

In 1968, the American Standard Code for Information Interchange, better known byits acronym ASCII, was standardized. ASCII defined numeric codes for variouscharacters, with the numeric values running from 0 to 127. For example, thelowercase letter ‘a’ is assigned 97 as its code value.

ASCII was an American-developed standard, so it only defined unaccentedcharacters. There was an ‘e’, but no ‘é’ or ‘Í’. This meant that languageswhich required accented characters couldn’t be faithfully represented in ASCII.(Actually the missing accents matter for English, too, which contains words suchas ‘naïve’ and ‘café’, and some publications have house styles which requirespellings such as ‘coöperate’.)

For a while people just wrote programs that didn’t display accents.In the mid-1980s an Apple II BASIC program written by a French speakermight have lines like these:

PRINT"FICHIER EST COMPLETE."PRINT"CARACTERE NON ACCEPTE."

Those messages should contain accents (completé, caractère, accepté),and they just look wrong to someone who can read French.

In the 1980s, almost all personal computers were 8-bit, meaning that bytes couldhold values ranging from 0 to 255. ASCII codes only went up to 127, so somemachines assigned values between 128 and 255 to accented characters. Differentmachines had different codes, however, which led to problems exchanging files.Eventually various commonly used sets of values for the 128–255 range emerged.Some were true standards, defined by the International Standards Organization,and some werede facto conventions that were invented by one company oranother and managed to catch on.

255 characters aren’t very many. For example, you can’t fit both the accentedcharacters used in Western Europe and the Cyrillic alphabet used for Russianinto the 128–255 range because there are more than 127 such characters.

You could write files using different codes (all your Russian files in a codingsystem called KOI8, all your French files in a different coding system calledLatin1), but what if you wanted to write a French document that quotes someRussian text? In the 1980s people began to want to solve this problem, and theUnicode standardization effort began.

Unicode started out using 16-bit characters instead of 8-bit characters. 16bits means you have 2^16 = 65,536 distinct values available, making it possibleto represent many different characters from many different alphabets; an initialgoal was to have Unicode contain the alphabets for every single human language.It turns out that even 16 bits isn’t enough to meet that goal, and the modernUnicode specification uses a wider range of codes, 0 through 1,114,111 (0x10FFFF in base 16).

There’s a related ISO standard, ISO 10646. Unicode and ISO 10646 wereoriginally separate efforts, but the specifications were merged with the 1.1revision of Unicode.

(This discussion of Unicode’s history is highly simplified. Theprecise historical details aren’t necessary for understanding how touse Unicode effectively, but if you’re curious, consult the Unicodeconsortium site listed in the References ortheWikipedia entry for Unicodefor more information.)

Definitions

Acharacter is the smallest possible component of a text. ‘A’, ‘B’, ‘C’,etc., are all different characters. So are ‘È’ and ‘Í’. Characters areabstractions, and vary depending on the language or context you’re talkingabout. For example, the symbol for ohms (Ω) is usually drawn much like thecapital letter omega (Ω) in the Greek alphabet (they may even be the same insome fonts), but these are two different characters that have differentmeanings.

The Unicode standard describes how characters are represented bycodepoints. A code point is an integer value, usually denoted in base 16. In thestandard, a code point is written using the notationU+12CA to mean thecharacter with value0x12ca (4,810 decimal). The Unicode standard containsa lot of tables listing characters and their corresponding code points:

0061    'a'; LATIN SMALL LETTER A0062    'b'; LATIN SMALL LETTER B0063    'c'; LATIN SMALL LETTER C...007B    '{'; LEFT CURLY BRACKET

Strictly, these definitions imply that it’s meaningless to say ‘this ischaracterU+12CA‘.U+12CA is a code point, which represents some particularcharacter; in this case, it represents the character ‘ETHIOPIC SYLLABLE WI’. Ininformal contexts, this distinction between code points and characters willsometimes be forgotten.

A character is represented on a screen or on paper by a set of graphicalelements that’s called aglyph. The glyph for an uppercase A, for example,is two diagonal strokes and a horizontal stroke, though the exact details willdepend on the font being used. Most Python code doesn’t need to worry aboutglyphs; figuring out the correct glyph to display is generally the job of a GUItoolkit or a terminal’s font renderer.

Encodings

To summarize the previous section: a Unicode string is a sequence of codepoints, which are numbers from 0 through0x10FFFF (1,114,111 decimal). Thissequence needs to be represented as a set of bytes (meaning, valuesfrom 0 through 255) in memory. The rules for translating a Unicode stringinto a sequence of bytes are called anencoding.

The first encoding you might think of is an array of 32-bit integers. In thisrepresentation, the string “Python” would look like this:

   P           y           t           h           o           n0x50 00 00 00 79 00 00 00 74 00 00 00 68 00 00 00 6f 00 00 00 6e 00 00 00   0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

This representation is straightforward but using it presents a number ofproblems.

  1. It’s not portable; different processors order the bytes differently.
  2. It’s very wasteful of space. In most texts, the majority of the code pointsare less than 127, or less than 255, so a lot of space is occupied by0x00bytes. The above string takes 24 bytes compared to the 6 bytes needed for anASCII representation. Increased RAM usage doesn’t matter too much (desktopcomputers have gigabytes of RAM, and strings aren’t usually that large), butexpanding our usage of disk and network bandwidth by a factor of 4 isintolerable.
  3. It’s not compatible with existing C functions such asstrlen(), so a newfamily of wide string functions would need to be used.
  4. Many Internet standards are defined in terms of textual data, and can’thandle content with embedded zero bytes.

Generally people don’t use this encoding, instead choosing otherencodings that are more efficient and convenient. UTF-8 is probablythe most commonly supported encoding; it will be discussed below.

Encodings don’t have to handle every possible Unicode character, and mostencodings don’t. The rules for converting a Unicode string into the ASCIIencoding, for example, are simple; for each code point:

  1. If the code point is < 128, each byte is the same as the value of the codepoint.
  2. If the code point is 128 or greater, the Unicode string can’t be representedin this encoding. (Python raises aUnicodeEncodeError exception in thiscase.)

Latin-1, also known as ISO-8859-1, is a similar encoding. Unicode code points0–255 are identical to the Latin-1 values, so converting to this encoding simplyrequires converting code points to byte values; if a code point larger than 255is encountered, the string can’t be encoded into Latin-1.

Encodings don’t have to be simple one-to-one mappings like Latin-1. ConsiderIBM’s EBCDIC, which was used on IBM mainframes. Letter values weren’t in oneblock: ‘a’ through ‘i’ had values from 129 to 137, but ‘j’ through ‘r’ were 145through 153. If you wanted to use EBCDIC as an encoding, you’d probably usesome sort of lookup table to perform the conversion, but this is largely aninternal detail.

UTF-8 is one of the most commonly used encodings. UTF stands for “UnicodeTransformation Format”, and the ‘8’ means that 8-bit numbers are used in theencoding. (There are also a UTF-16 and UTF-32 encodings, but they are lessfrequently used than UTF-8.) UTF-8 uses the following rules:

  1. If the code point is < 128, it’s represented by the corresponding byte value.
  2. If the code point is >= 128, it’s turned into a sequence of two, three, orfour bytes, where each byte of the sequence is between 128 and 255.

UTF-8 has several convenient properties:

  1. It can handle any Unicode code point.
  2. A Unicode string is turned into a string of bytes containing no embedded zerobytes. This avoids byte-ordering issues, and means UTF-8 strings can beprocessed by C functions such asstrcpy() and sent through protocols thatcan’t handle zero bytes.
  3. A string of ASCII text is also valid UTF-8 text.
  4. UTF-8 is fairly compact; the majority of commonly used characters can berepresented with one or two bytes.
  5. If bytes are corrupted or lost, it’s possible to determine the start of thenext UTF-8-encoded code point and resynchronize. It’s also unlikely thatrandom 8-bit data will look like valid UTF-8.

References

TheUnicode Consortium site has character charts, aglossary, and PDF versions of the Unicode specification. Be prepared for somedifficult reading.A chronology of theorigin and development of Unicode is also available on the site.

To help understand the standard, Jukka Korpela has writtenan introductoryguide to reading theUnicode character tables.

Anothergood introductory articlewas written by Joel Spolsky.If this introduction didn’t make things clear to you, you should tryreading this alternate article before continuing.

Wikipedia entries are often helpful; see the entries for “character encoding” andUTF-8, for example.

Python’s Unicode Support

Now that you’ve learned the rudiments of Unicode, we can look at Python’sUnicode features.

The String Type

Since Python 3.0, the language features astr type that contain Unicodecharacters, meaning any string created using"unicoderocks!",'unicoderocks!', or the triple-quoted string syntax is stored as Unicode.

The default encoding for Python source code is UTF-8, so you can simplyinclude a Unicode character in a string literal:

try:withopen('/tmp/input.txt','r')asf:...exceptIOError:# 'File not found' error message.print("Fichier non trouvé")

You can use a different encoding from UTF-8 by putting a specially-formattedcomment as the first or second line of the source code:

# -*- coding: <encoding name> -*-

Side note: Python 3 also supports using Unicode characters in identifiers:

répertoire="/tmp/records.log"withopen(répertoire,"w")asf:f.write("test\n")

If you can’t enter a particular character in your editor or want tokeep the source code ASCII-only for some reason, you can also useescape sequences in string literals. (Depending on your system,you may see the actual capital-delta glyph instead of a u escape.)

>>>"\N{GREEK CAPITAL LETTER DELTA}"# Using the character name'\u0394'>>>"\u0394"# Using a 16-bit hex value'\u0394'>>>"\U00000394"# Using a 32-bit hex value'\u0394'

In addition, one can create a string using thedecode() method ofbytes. This method takes anencoding argument, such asUTF-8,and optionally anerrors argument.

Theerrors argument specifies the response when the input string can’t beconverted according to the encoding’s rules. Legal values for this argument are'strict' (raise aUnicodeDecodeError exception),'replace' (useU+FFFD,REPLACEMENTCHARACTER), or'ignore' (just leave thecharacter out of the Unicode result).The following examples show the differences:

>>>b'\x80abc'.decode("utf-8","strict")Traceback (most recent call last):...UnicodeDecodeError:'utf-8' codec can't decode byte 0x80 in position 0:  invalid start byte>>>b'\x80abc'.decode("utf-8","replace")'\ufffdabc'>>>b'\x80abc'.decode("utf-8","ignore")'abc'

(In this code example, the Unicode replacement character has been replaced bya question mark because it may not be displayed on some systems.)

Encodings are specified as strings containing the encoding’s name. Python 3.2comes with roughly 100 different encodings; see the Python Library Reference atStandard Encodings for a list. Some encodings have multiple names; forexample,'latin-1','iso_8859_1' and'8859‘ are all synonyms forthe same encoding.

One-character Unicode strings can also be created with thechr()built-in function, which takes integers and returns a Unicode string of length 1that contains the corresponding code point. The reverse operation is thebuilt-inord() function that takes a one-character Unicode string andreturns the code point value:

>>>chr(57344)'\ue000'>>>ord('\ue000')57344

Converting to Bytes

The opposite method ofbytes.decode() isstr.encode(),which returns abytes representation of the Unicode string, encoded in therequestedencoding.

Theerrors parameter is the same as the parameter of thedecode() method but supports a few more possible handlers. As well as'strict','ignore', and'replace' (which in this caseinserts a question mark instead of the unencodable character), there isalso'xmlcharrefreplace' (inserts an XML character reference) andbackslashreplace (inserts a\uNNNN escape sequence).

The following example shows the different results:

>>>u=chr(40960)+'abcd'+chr(1972)>>>u.encode('utf-8')b'\xea\x80\x80abcd\xde\xb4'>>>u.encode('ascii')Traceback (most recent call last):...UnicodeEncodeError:'ascii' codec can't encode character '\ua000' in  position 0: ordinal not in range(128)>>>u.encode('ascii','ignore')b'abcd'>>>u.encode('ascii','replace')b'?abcd?'>>>u.encode('ascii','xmlcharrefreplace')b'&#40960;abcd&#1972;'>>>u.encode('ascii','backslashreplace')b'\\ua000abcd\\u07b4'

The low-level routines for registering and accessing the availableencodings are found in thecodecs module. Implementing newencodings also requires understanding thecodecs module.However, the encoding and decoding functions returned by this moduleare usually more low-level than is comfortable, and writing new encodingsis a specialized task, so the module won’t be covered in this HOWTO.

Unicode Literals in Python Source Code

In Python source code, specific Unicode code points can be written using the\u escape sequence, which is followed by four hex digits giving the codepoint. The\U escape sequence is similar, but expects eight hex digits,not four:

>>>s="a\xac\u1234\u20ac\U00008000"...#     ^^^^ two-digit hex escape...#         ^^^^^^ four-digit Unicode escape...#                     ^^^^^^^^^^ eight-digit Unicode escape>>>[ord(c)forcins][97, 172, 4660, 8364, 32768]

Using escape sequences for code points greater than 127 is fine in small doses,but becomes an annoyance if you’re using many accented characters, as you wouldin a program with messages in French or some other accent-using language. Youcan also assemble strings using thechr() built-in function, but this iseven more tedious.

Ideally, you’d want to be able to write literals in your language’s naturalencoding. You could then edit Python source code with your favorite editorwhich would display the accented characters naturally, and have the rightcharacters used at runtime.

Python supports writing source code in UTF-8 by default, but you can use almostany encoding if you declare the encoding being used. This is done by includinga special comment as either the first or second line of the source file:

#!/usr/bin/env python# -*- coding: latin-1 -*-u='abcdé'print(ord(u[-1]))

The syntax is inspired by Emacs’s notation for specifying variables local to afile. Emacs supports many different variables, but Python only supports‘coding’. The-*- symbols indicate to Emacs that the comment is special;they have no significance to Python but are a convention. Python looks forcoding:name orcoding=name in the comment.

If you don’t include such a comment, the default encoding used will be UTF-8 asalready mentioned. See alsoPEP 263 for more information.

Unicode Properties

The Unicode specification includes a database of information about code points.For each defined code point, the information includes the character’sname, its category, the numeric value if applicable (Unicode has charactersrepresenting the Roman numerals and fractions such as one-third andfour-fifths). There are also properties related to the code point’s use inbidirectional text and other display-related properties.

The following program displays some information about several characters, andprints the numeric value of one particular character:

importunicodedatau=chr(233)+chr(0x0bf2)+chr(3972)+chr(6000)+chr(13231)fori,cinenumerate(u):print(i,'%04x'%ord(c),unicodedata.category(c),end=" ")print(unicodedata.name(c))# Get numeric value of second characterprint(unicodedata.numeric(u[1]))

When run, this prints:

0 00e9 Ll LATIN SMALL LETTER E WITH ACUTE1 0bf2 No TAMIL NUMBER ONE THOUSAND2 0f84 Mn TIBETAN MARK HALANTA3 1770 Lo TAGBANWA LETTER SA4 33af So SQUARE RAD OVER S SQUARED1000.0

The category codes are abbreviations describing the nature of the character.These are grouped into categories such as “Letter”, “Number”, “Punctuation”, or“Symbol”, which in turn are broken up into subcategories. To take the codesfrom the above output,'Ll' means ‘Letter, lowercase’,'No' means“Number, other”,'Mn' is “Mark, nonspacing”, and'So' is “Symbol,other”. Seethe General Category Values section of the Unicode Character Database documentation for alist of category codes.

Unicode Regular Expressions

The regular expressions supported by there module can be providedeither as bytes or strings. Some of the special character sequences such as\d and\w have different meanings depending on whetherthe pattern is supplied as bytes or a string. For example,\d will match the characters[0-9] in bytes butin strings will match any character that’s in the'Nd' category.

The string in this example has the number 57 written in both Thai andArabic numerals:

importrep=re.compile('\d+')s="Over\u0e55\u0e57 57 flavours"m=p.search(s)print(repr(m.group()))

When executed,\d+ will match the Thai numerals and print themout. If you supply there.ASCII flag tocompile(),\d+ will match the substring “57” instead.

Similarly,\w matches a wide variety of Unicode characters butonly[a-zA-Z0-9_] in bytes or ifre.ASCII is supplied,and\s will match either Unicode whitespace characters or[\t\n\r\f\v].

References

Some good alternative discussions of Python’s Unicode support are:

Thestr type is described in the Python library reference atText Sequence Type — str.

The documentation for theunicodedata module.

The documentation for thecodecs module.

Marc-André Lemburg gavea presentation titled “Python and Unicode” (PDF slides) atEuroPython 2002. The slides are an excellent overview of the designof Python 2’s Unicode features (where the Unicode string type iscalledunicode and literals start withu).

Reading and Writing Unicode Data

Once you’ve written some code that works with Unicode data, the next problem isinput/output. How do you get Unicode strings into your program, and how do youconvert Unicode into a form suitable for storage or transmission?

It’s possible that you may not need to do anything depending on your inputsources and output destinations; you should check whether the libraries used inyour application support Unicode natively. XML parsers often return Unicodedata, for example. Many relational databases also support Unicode-valuedcolumns and can return Unicode values from an SQL query.

Unicode data is usually converted to a particular encoding before it getswritten to disk or sent over a socket. It’s possible to do all the workyourself: open a file, read an 8-bit bytes object from it, and convert the byteswithbytes.decode(encoding). However, the manual approach is not recommended.

One problem is the multi-byte nature of encodings; one Unicode character can berepresented by several bytes. If you want to read the file in arbitrary-sizedchunks (say, 1024 or 4096 bytes), you need to write error-handling code to catch the casewhere only part of the bytes encoding a single Unicode character are read at theend of a chunk. One solution would be to read the entire file into memory andthen perform the decoding, but that prevents you from working with files thatare extremely large; if you need to read a 2 GiB file, you need 2 GiB of RAM.(More, really, since for at least a moment you’d need to have both the encodedstring and its Unicode version in memory.)

The solution would be to use the low-level decoding interface to catch the caseof partial coding sequences. The work of implementing this has already beendone for you: the built-inopen() function can return a file-like objectthat assumes the file’s contents are in a specified encoding and accepts Unicodeparameters for methods such asread() andwrite(). This works throughopen()‘sencoding anderrors parameters which are interpreted just like those instr.encode()andbytes.decode().

Reading Unicode from a file is therefore simple:

withopen('unicode.txt',encoding='utf-8')asf:forlineinf:print(repr(line))

It’s also possible to open files in update mode, allowing both reading andwriting:

withopen('test',encoding='utf-8',mode='w+')asf:f.write('\u4500 blah blah blah\n')f.seek(0)print(repr(f.readline()[:1]))

The Unicode characterU+FEFF is used as a byte-order mark (BOM), and is oftenwritten as the first character of a file in order to assist with autodetectionof the file’s byte ordering. Some encodings, such as UTF-16, expect a BOM to bepresent at the start of a file; when such an encoding is used, the BOM will beautomatically written as the first character and will be silently dropped whenthe file is read. There are variants of these encodings, such as ‘utf-16-le’and ‘utf-16-be’ for little-endian and big-endian encodings, that specify oneparticular byte ordering and don’t skip the BOM.

In some areas, it is also convention to use a “BOM” at the start of UTF-8encoded files; the name is misleading since UTF-8 is not byte-order dependent.The mark simply announces that the file is encoded in UTF-8. Use the‘utf-8-sig’ codec to automatically skip the mark if present for reading suchfiles.

Unicode filenames

Most of the operating systems in common use today support filenames that containarbitrary Unicode characters. Usually this is implemented by converting theUnicode string into some encoding that varies depending on the system. Forexample, Mac OS X uses UTF-8 while Windows uses a configurable encoding; onWindows, Python uses the name “mbcs” to refer to whatever the currentlyconfigured encoding is. On Unix systems, there will only be a filesystemencoding if you’ve set theLANG orLC_CTYPE environment variables; ifyou haven’t, the default encoding is UTF-8.

Thesys.getfilesystemencoding() function returns the encoding to use onyour current system, in case you want to do the encoding manually, but there’snot much reason to bother. When opening a file for reading or writing, you canusually just provide the Unicode string as the filename, and it will beautomatically converted to the right encoding for you:

filename='filename\u4500abc'withopen(filename,'w')asf:f.write('blah\n')

Functions in theos module such asos.stat() will also accept Unicodefilenames.

Theos.listdir() function returns filenames and raises an issue: should it returnthe Unicode version of filenames, or should it return bytes containingthe encoded versions?os.listdir() will do both, depending on whether youprovided the directory path as bytes or a Unicode string. If you pass aUnicode string as the path, filenames will be decoded using the filesystem’sencoding and a list of Unicode strings will be returned, while passing a bytepath will return the filenames as bytes. For example,assuming the default filesystem encoding is UTF-8, running the followingprogram:

fn='filename\u4500abc'f=open(fn,'w')f.close()importosprint(os.listdir(b'.'))print(os.listdir('.'))

will produce the following output:

amk:~$ python t.py[b'filename\xe4\x94\x80abc', ...]['filename\u4500abc', ...]

The first list contains UTF-8-encoded filenames, and the second list containsthe Unicode versions.

Note that on most occasions, the Unicode APIs should be used. The bytes APIsshould only be used on systems where undecodable file names can be present,i.e. Unix systems.

Tips for Writing Unicode-aware Programs

This section provides some suggestions on writing software that deals withUnicode.

The most important tip is:

Software should only work with Unicode strings internally, decoding the inputdata as soon as possible and encoding the output only at the end.

If you attempt to write processing functions that accept both Unicode and bytestrings, you will find your program vulnerable to bugs wherever you combine thetwo different kinds of strings. There is no automatic encoding or decoding: ifyou do e.g.str+bytes, aTypeError will be raised.

When using data coming from a web browser or some other untrusted source, acommon technique is to check for illegal characters in a string before using thestring in a generated command line or storing it in a database. If you’re doingthis, be careful to check the decoded string, not the encoded bytes data;some encodings may have interesting properties, such as not being bijectiveor not being fully ASCII-compatible. This is especially true if the inputdata also specifies the encoding, since the attacker can then choose aclever way to hide malicious text in the encoded bytestream.

Converting Between File Encodings

TheStreamRecoder class can transparently convert betweenencodings, taking a stream that returns data in encoding #1and behaving like a stream returning data in encoding #2.

For example, if you have an input filef that’s in Latin-1, youcan wrap it with aStreamRecoder to return bytes encoded inUTF-8:

new_f=codecs.StreamRecoder(f,# en/decoder: used by read() to encode its results and# by write() to decode its input.codecs.getencoder('utf-8'),codecs.getdecoder('utf-8'),# reader/writer: used to read and write to the stream.codecs.getreader('latin-1'),codecs.getwriter('latin-1'))

Files in an Unknown Encoding

What can you do if you need to make a change to a file, but don’t knowthe file’s encoding? If you know the encoding is ASCII-compatible andonly want to examine or modify the ASCII parts, you can open the filewith thesurrogateescape error handler:

withopen(fname,'r',encoding="ascii",errors="surrogateescape")asf:data=f.read()# make changes to the string 'data'withopen(fname+'.new','w',encoding="ascii",errors="surrogateescape")asf:f.write(data)

Thesurrogateescape error handler will decode any non-ASCII bytesas code points in the Unicode Private Use Area ranging from U+DC80 toU+DCFF. These private code points will then be turned back into thesame bytes when thesurrogateescape error handler is used whenencoding the data and writing it back out.

References

One section ofMastering Python 3 Input/Output, a PyCon 2010 talk by David Beazley, discusses text processing and binary data handling.

ThePDF slides for Marc-André Lemburg’s presentation “Writing Unicode-aware Applications in Python”discuss questions of character encodings as well as how to internationalizeand localize an application. These slides cover Python 2.x only.

The Guts of Unicode in Python is a PyCon 2013 talk by Benjamin Peterson that discusses the internal Unicode representation in Python 3.3.

Acknowledgements

The initial draft of this document was written by Andrew Kuchling.It has since been revised further by Alexander Belopolsky, Georg Brandl,Andrew Kuchling, and Ezio Melotti.

Thanks to the following people who have noted errors or offeredsuggestions on this article: Éric Araujo, Nicholas Bastin, NickCoghlan, Marius Gedminas, Kent Johnson, Ken Krugler, Marc-AndréLemburg, Martin von Löwis, Terry J. Reedy, Chad Whitacre.

Table Of Contents

Previous topic

Sorting HOW TO

Next topic

HOWTO Fetch Internet Resources Using The urllib Package

This Page

Quick search

Enter search terms or a module, class or function name.

Navigation

©Copyright 1990-2017, Python Software Foundation.
The Python Software Foundation is a non-profit corporation.Please donate.
Last updated on Sep 19, 2017.Found a bug?
Created usingSphinx 1.2.

[8]ページ先頭

©2009-2025 Movatter.jp