<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # Unicode 和傳遞字符串 > 原文: [http://docs.cython.org/en/latest/src/tutorial/strings.html](http://docs.cython.org/en/latest/src/tutorial/strings.html) 與 Python 3 中的字符串語義類似,Cython 嚴格區分字節字符串和 unicode 字符串。最重要的是,這意味著默認情況下,字節字符串和 unicode 字符串之間沒有自動轉換(Python 2 在字符串操作中的作用除外)。所有編碼和解碼必須通過顯式編碼/解碼步驟。為了在簡單的情況下簡化 Python 和 C 字符串之間的轉換,模塊級`c_string_type`和`c_string_encoding`指令可用于隱式插入這些編碼/解碼步驟。 ## Cython 代碼中的 Python 字符串類型 Cython 支持四種 Python 字符串類型: [`bytes`](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.7)") , [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") ,`unicode`和`basestring`。 [`bytes`](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.7)") 和`unicode`類型是普通 Python 2.x 中已知的特定類型(在 Python 3 中命名為 [`bytes`](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.7)") 和 [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") )。此外,Cython 還支持 [`bytearray`](https://docs.python.org/3/library/stdtypes.html#bytearray "(in Python v3.7)") 類型,其行為類似于 [`bytes`](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.7)") 類型,除了它是可變的。 [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") 類型的特殊之處在于它是 Python 2 中的字節字符串和 Python 3 中的 Unicode 字符串(用于使用語言級別 2 編譯的 Cython 代碼,即默認值)。意思是,它總是與 Python 運行時自身調用的類型 [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") 完全對應。因此,在 Python 2 中, [`bytes`](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.7)") 和 [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") 都代表字節串類型,而在 Python 3 中, [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") 和`unicode` ]表示 Python Unicode 字符串類型。切換是在 C 編譯時進行的,用于運行 Cython 的 Python 版本是不相關的。 在使用語言級別 3 編譯 Cython 代碼時, [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") 類型在 Cython 編譯時使用完全符合 Unicode 字符串類型進行標識,即在運行時無法識別 [`bytes`](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.7)") 在 Python 2 中。 請注意, [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") 類型與 Python 2 中的`unicode`類型不兼容,即您無法將 Unicode 字符串分配給鍵入的變量或參數 [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") 。該嘗試將在運行時導致編譯時錯誤(如果可檢測)或 [`TypeError`](https://docs.python.org/3/library/exceptions.html#TypeError "(in Python v3.7)") 異常。因此,在必須與 Python 2 兼容的代碼中靜態鍵入字符串變量時應該小心,因為此 Python 版本允許混合字節字符串和數據的 unicode 字符串,用戶通常希望代碼能夠同時使用這兩者。僅針對 Python 3 的代碼可以安全地將變量和參數鍵入為 [`bytes`](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.7)") 或`unicode`。 `basestring`類型表示 [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") 和`unicode`類型,即 Python 2 和 Python 3 中的所有 Python 文本字符串類型。這可用于鍵入通常包含 Unicode 文本的文本變量(至少在 Python 3)中,但為了向后兼容的原因,必須另外接受 Python 2 中的 [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") 類型。它與 [`bytes`](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.7)") 類型不兼容。它的使用在普通的 Cython 代碼中應該是罕見的,因為通用 [`object`](https://docs.python.org/3/library/functions.html#object "(in Python v3.7)") 類型(即無類型代碼)通常足夠好并且具有支持字符串子類型的分配的額外優點。在 Cython 0.20 中添加了對`basestring`類型的支持。 ## 字符串文字 Cython 了解所有 Python 字符串類型前綴: * 字節串的`b'bytes'` * Unicode 字符串的`u'text'` * `f'formatted {value}'`用于格式化的 Unicode 字符串文字,由 [**PEP 498** ](https://www.python.org/dev/peps/pep-0498)定義(在 Cython 0.24 中添加) 當使用語言級別 2 和`unicode`對象(即 Python 3 [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") )進行語言級別 3 編譯時,未加前綴的字符串文字將成為 [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") 對象。 ## 關于 C 字符串的一般說明 在許多用例中,C 字符串(即字符串指針)速度慢且繁瑣。首先,它們通常需要以某種方式進行手動內存管理,這使得它更有可能在代碼中引入錯誤。 然后,Python 字符串對象緩存它們的長度,因此請求它(例如,驗證索引訪問的邊界或將兩個字符串連接成一個)是一種有效的恒定時間操作。相反,調用`strlen()`從 C 字符串獲取此信息需要線性時間,這使得對 C 字符串的許多操作相當昂貴。 關于文本處理,Python 內置了對 Unicode 的支持,C 完全缺乏。如果您正在處理 Unicode 文本,那么使用 Python Unicode 字符串對象通常比嘗試使用 C 字符串中的編碼數據更好。 Cython 使這非常簡單有效。 一般來說:除非您知道自己在做什么,否則請盡量避免使用 C 字符串,而應使用 Python 字符串對象。對此明顯的例外是從外部 C 代碼來回傳遞它們。此外,C ++字符串也記住它們的長度,因此它們可以在某些情況下提供 Python 字節對象的合適替代,例如,在明確定義的上下文中不需要引用計數時。 ## 傳遞字節串 我們在名為`c_func.pyx`的文件中聲明了虛擬 C 函數,我們將在本教程中重復使用它們: ```py from libc.stdlib cimport malloc from libc.string cimport strcpy, strlen cdef char* hello_world = 'hello world' cdef Py_ssize_t n = strlen(hello_world) cdef char* c_call_returning_a_c_string(): cdef char* c_string = <char *> malloc((n + 1) * sizeof(char)) if not c_string: raise MemoryError() strcpy(c_string, hello_world) return c_string cdef void get_a_c_string(char** c_string_ptr, Py_ssize_t *length): c_string_ptr[0] = <char *> malloc((n + 1) * sizeof(char)) if not c_string_ptr[0]: raise MemoryError() strcpy(c_string_ptr[0], hello_world) length[0] = n ``` 我們制作了相應的`c_func.pxd`以便能夠實現這些功能: ```py cdef char* c_call_returning_a_c_string() cdef void get_a_c_string(char** c_string, Py_ssize_t *length) ``` 在 C 代碼和 Python 之間傳遞字節字符串非常容易。從 C 庫接收字節字符串時,只需將其轉換為 Python 變量,即可讓 Cython 將其轉換為 Python 字節字符串: ```py from c_func cimport c_call_returning_a_c_string cdef char* c_string = c_call_returning_a_c_string() cdef bytes py_string = c_string ``` 轉換為 [`object`](https://docs.python.org/3/library/functions.html#object "(in Python v3.7)") 或 [`bytes`](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.7)") 的類型將執行相同的操作: ```py py_string = <bytes> c_string ``` 這將創建一個 Python 字節字符串對象,該對象包含原始 C 字符串的副本。它可以安全地在 Python 代碼中傳遞,并在最后一次引用超出范圍時進行垃圾收集。重要的是要記住,字符串中的空字節充當終止符,如 C 中通常所知。因此,上述內容僅適用于不包含空字節的 C 字符串。 除了不使用空字節之外,對于長字符串,上述也是非常低效的,因為 Cython 必須首先在 C 字符串上調用`strlen()`以通過計算字節直到終止空字節來找出長度。在許多情況下,用戶代碼已經知道長度,例如因為 C 函數返回了它。在這種情況下,通過切片 C 字符串告訴 Cython 確切的字節數會更有效。這是一個例子: ```py from libc.stdlib cimport free from c_func cimport get_a_c_string def main(): cdef char* c_string = NULL cdef Py_ssize_t length = 0 # get pointer and length from a C function get_a_c_string(&c_string, &length) try: py_bytes_string = c_string[:length] # Performs a copy of the data finally: free(c_string) ``` 這里,不需要額外的字節計數,`c_string`中的`length`字節將被復制到 Python 字節對象中,包括任何空字節。請記住,在這種情況下,切片索引被認為是準確的,并且沒有進行邊界檢查,因此不正確的切片索引將導致數據損壞和崩潰。 請注意,Python 字節字符串的創建可能會因異常而失敗,例如由于記憶力不足。如果轉換后需要`free()`字符串,則應將賦值包裝在 try-finally 結構中: ```py from libc.stdlib cimport free from c_func cimport c_call_returning_a_c_string cdef bytes py_string cdef char* c_string = c_call_returning_a_c_string() try: py_string = c_string finally: free(c_string) ``` 要將字節字符串轉換回 C `char*`,請使用相反的賦值: ```py cdef char* other_c_string = py_string # other_c_string is a 0-terminated string. ``` 這是一個非常快速的操作,之后`other_c_string`指向 Python 字符串本身的字節字符串緩沖區。它與 Python 字符串的生命周期有關。當 Python 字符串被垃圾收集時,指針變為無效。因此,只要`char*`正在使用,就必須保持對 Python 字符串的引用。通常,這只會調用一個接收指針作為參數的 C 函數。但是,當 C 函數存儲指針供以后使用時,必須特別小心。除了保持對字符串對象的 Python 引用外,不需要手動內存管理。 從 Cython 0.20 開始,支持 [`bytearray`](https://docs.python.org/3/library/stdtypes.html#bytearray "(in Python v3.7)") 類型并以與 [`bytes`](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.7)") 類型相同的方式強制執行。但是,在 C 上下文中使用它時,在將對象緩沖區轉換為 C 字符串指針后,必須特別注意不要增大或縮小對象緩沖區。這些修改可以更改內部緩沖區地址,這將使指針無效。 ## 接受 Python 代碼中的字符串 另一方面,從 Python 代碼接收輸入,初看起來可能看起來很簡單,因為它只處理對象。但是,在不使 API 太窄或太不安全的情況下做到這一點可能并不完全明顯。 在 API 僅處理字節字符串(即二進制數據或編碼文本)的情況下,最好不要將輸入參數鍵入 [`bytes`](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.7)") ,因為這會將允許的輸入限制為準確該類型并排除子類型和其他類型的字節容器,例如 [`bytearray`](https://docs.python.org/3/library/stdtypes.html#bytearray "(in Python v3.7)") 對象或內存視圖。 根據數據的處理方式(以及在何處),最好接收一維存儲器視圖,例如, ```py def process_byte_data(unsigned char[:] data): length = data.shape[0] first_byte = data[0] slice_view = data[1:-1] # ... ``` Cython 的內存視圖在 [Typed Memoryviews](../userguide/memoryviews.html)中有更詳細的描述,但上面的例子已經顯示了 1 維字節視圖的大部分相關功能。它們允許有效地處理數組并接受任何可以將其自身解壓縮到字節緩沖區中的內容,而無需中間復制。處理后的內容最終可以在內存視圖本身(或其中的一部分)中返回,但通常最好將數據復制回平坦且簡單的 [`bytes`](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.7)") 或 [`bytearray`](https://docs.python.org/3/library/stdtypes.html#bytearray "(in Python v3.7)") 對象,特別是當只返回一個小切片時。由于內存視圖不會復制數據,因此它們會保持整個原始緩沖區的活動狀態。這里的一般想法是通過接受任何類型的字節緩沖區來自由輸入,但通過返回一個簡單,適應良好的對象來嚴格控制輸出。這可以簡單地完成如下: ```py def process_byte_data(unsigned char[:] data): # ... process the data, here, dummy processing. cdef bint return_all = (data[0] == 108) if return_all: return bytes(data) else: # example for returning a slice return bytes(data[5:7]) ``` 如果字節輸入實際上是編碼文本,并且進一步處理應該在 Unicode 級別進行,那么正確的做法是直接解碼輸入。這幾乎只是 Python 2.x 中的一個問題,Python 代碼期望它可以將帶有編碼文本的字節串( [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") )傳遞到文本 API 中。由于這通常發生在模塊 API 的多個位置,因此輔助函數幾乎總是可行的,因為它允許以后輕松調整輸入規范化過程。 這種輸入規范化功能通常類似于以下內容: ```py # to_unicode.pyx from cpython.version cimport PY_MAJOR_VERSION cdef unicode _text(s): if type(s) is unicode: # Fast path for most common case(s). return <unicode>s elif PY_MAJOR_VERSION < 3 and isinstance(s, bytes): # Only accept byte strings as text input in Python 2.x, not in Py3. return (<bytes>s).decode('ascii') elif isinstance(s, unicode): # We know from the fast path above that 's' can only be a subtype here. # An evil cast to <unicode> might still work in some(!) cases, # depending on what the further processing does. To be safe, # we can always create a copy instead. return unicode(s) else: raise TypeError("Could not convert to unicode.") ``` 然后應該像這樣使用: ```py from to_unicode cimport _text def api_func(s): text_input = _text(s) # ... ``` 類似地,如果進一步處理發生在字節級別,但是應該接受 Unicode 字符串輸入,那么如果您使用內存視圖,則以下可能有效: ```py # define a global name for whatever char type is used in the module ctypedef unsigned char char_type cdef char_type[:] _chars(s): if isinstance(s, unicode): # encode to the specific encoding used inside of the module s = (<unicode>s).encode('utf8') return s ``` 在這種情況下,您可能希望另外確保字節串輸入確實使用正確的編碼,例如如果需要純 ASCII 輸入數據,可以在循環中運行緩沖區并檢查每個字節的最高位。這也應該在輸入規范化函數中完成。 ## 處理“const” 許多 C 庫在其 API 中使用`const`修飾符來聲明它們不會修改字符串,或者要求用戶不得修改它們返回的字符串,例如: ```py typedef const char specialChar; int process_string(const char* s); const unsigned char* look_up_cached_string(const unsigned char* key); ``` Cython 支持該語言中的`const`修飾符,因此您可以直接聲明上述函數,如下所示: ```py cdef extern from "someheader.h": ctypedef const char specialChar int process_string(const char* s) const unsigned char* look_up_cached_string(const unsigned char* key) ``` ## 將字節解碼為文本 如果您的代碼只處理字符串中的二進制數據,那么最初提供的傳遞和接收 C 字符串的方法就足夠了。但是,當我們處理編碼文本時,最好在接收時將 C 字節字符串解碼為 Python Unicode 字符串,并在出路時將 Python Unicode 字符串編碼為 C 字節字符串。 使用 Python 字節字符串對象,通常只需調用`bytes.decode()`方法將其解碼為 Unicode 字符串: ```py ustring = byte_string.decode('UTF-8') ``` Cython 允許您對 C 字符串執行相同操作,只要它不包含空字節: ```py from c_func cimport c_call_returning_a_c_string cdef char* some_c_string = c_call_returning_a_c_string() ustring = some_c_string.decode('UTF-8') ``` 并且,對于已知長度的字符串,更有效: ```py from c_func cimport get_a_c_string cdef char* c_string = NULL cdef Py_ssize_t length = 0 # get pointer and length from a C function get_a_c_string(&c_string, &length) ustring = c_string[:length].decode('UTF-8') ``` 當字符串包含空字節時,應該使用相同的字符串,例如當它使用像 UCS-4 這樣的編碼時,每個字符以四個字節編碼,其中大多數字符往往是 0。 同樣,如果提供切片索引,則不會進行邊界檢查,因此不正確的索引會導致數據損壞和崩潰。但是,使用負索引是可能的,并將調用`strlen()`以確定字符串長度。顯然,這僅適用于沒有內部空字節的 0 終止字符串。以 UTF-8 編碼的文本或 ISO-8859 編碼之一通常是一個很好的候選者。如果有疑問,最好傳遞“明顯”正確的索引,而不是依賴于數據是否符合預期。 通常的做法是在專用函數中包裝字符串轉換(以及一般的非平凡類型轉換),因為每當從 C 接收文本時,都需要以完全相同的方式完成。這可能如下所示: ```py from libc.stdlib cimport free cdef unicode tounicode(char* s): return s.decode('UTF-8', 'strict') cdef unicode tounicode_with_length( char* s, size_t length): return s[:length].decode('UTF-8', 'strict') cdef unicode tounicode_with_length_and_free( char* s, size_t length): try: return s[:length].decode('UTF-8', 'strict') finally: free(s) ``` 最有可能的是,根據要處理的字符串類型,您會更喜歡代碼中較短的函數名稱。不同類型的內容通常意味著在接收時處理它們的不同方式。為了使代碼更具可讀性并預測未來的更改,最好對不同類型的字符串使用單獨的轉換函數。 ## 將文本編碼為字節 反過來,將 Python unicode 字符串轉換為 C `char*`本身非常有效,假設您實際需要的是內存管理字節字符串: ```py py_byte_string = py_unicode_string.encode('UTF-8') cdef char* c_string = py_byte_string ``` 如前所述,這將指針指向 Python 字節字符串的字節緩沖區。嘗試在不保留對 Python 字節字符串的引用的情況下執行相同操作將失敗并出現編譯錯誤: ```py # this will not compile ! cdef char* c_string = py_unicode_string.encode('UTF-8') ``` 在這里,Cython 編譯器注意到代碼采用指向臨時字符串結果的指針,該結果將在賦值后進行垃圾回收。稍后訪問無效指針將讀取無效內存,并可能導致段錯誤。因此,Cython 將拒絕編譯此代碼。 ## C ++字符串 包裝 C ++庫時,字符串通常以`std::string`類的形式出現。與 C 字符串一樣,Python 字節字符串自動強制轉換為 C ++字符串: ```py # distutils: language = c++ from libcpp.string cimport string def get_bytes(): py_bytes_object = b'hello world' cdef string s = py_bytes_object s.append('abc') py_bytes_object = s return py_bytes_object ``` 內存管理情況與 C 中的情況不同,因為創建 C ++字符串會生成字符串對象隨后擁有的字符串緩沖區的獨立副本。因此,可以將臨時創建的 Python 對象直接轉換為 C ++字符串。使用此方法的常用方法是將 Python unicode 字符串編碼為 C ++字符串: ```py cdef string cpp_string = py_unicode_string.encode('UTF-8') ``` 請注意,這涉及一些開銷,因為它首先將 Unicode 字符串編碼為臨時創建的 Python 字節對象,然后將其緩沖區復制到新的 C ++字符串中。 另一方面,Cython 0.17 及更高版本提供了高效的解碼支持: ```py # distutils: language = c++ from libcpp.string cimport string def get_ustrings(): cdef string s = string(b'abcdefg') ustring1 = s.decode('UTF-8') ustring2 = s[2:-2].decode('UTF-8') return ustring1, ustring2 ``` 對于 C ++字符串,解碼片將始終考慮字符串的適當長度并應用 Python 切片語義(例如,為越界索引返回空字符串)。 ## 自動編碼和解碼 Cython 0.19 附帶兩個新指令:`c_string_type`和`c_string_encoding`。它們可用于更改 C / C ++字符串強制執行的 Python 字符串類型。默認情況下,它們僅強制執行字節類型,并且必須明確地進行編碼或解碼,如上所述。 有兩種用例不方便。首先,如果正在處理的所有 C 字符串(或大多數)包含文本,則從 Python unicode 對象自動編碼和解碼可以減少代碼開銷。在這種情況下,您可以將模塊中的`c_string_type`指令設置為`unicode`,將`c_string_encoding`指定為 C 代碼使用的編碼,例如: ```py # cython: c_string_type=unicode, c_string_encoding=utf8 cdef char* c_string = 'abcdefg' # implicit decoding: cdef object py_unicode_object = c_string # explicit conversion to Python bytes: py_bytes_object = <bytes>c_string ``` 第二個用例是當所有正在處理的 C 字符串只包含 ASCII 可編碼字符(例如數字)時,您希望代碼在 Python 2 中使用本機遺留字符串類型,而不是始終使用 Unicode。在這種情況下,您可以將字符串類型設置為 [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") : ```py # cython: c_string_type=str, c_string_encoding=ascii cdef char* c_string = 'abcdefg' # implicit decoding in Py3, bytes conversion in Py2: cdef object py_str_object = c_string # explicit conversion to Python bytes: py_bytes_object = <bytes>c_string # explicit conversion to Python unicode: py_bytes_object = <unicode>c_string ``` 另一個方向,即自動編碼為 C 字符串,僅支持 ASCII 和“默認編碼”,它通常是 Python 3 中的 UTF-8,通常是 Python 2 中的 ASCII。在這種情況下,CPython 通過保持一個來處理內存管理字符串的編碼副本與原始 unicode 字符串一起存活。否則,將無法以任何合理的方式限制編碼字符串的生命周期,從而使得從其中提取 C 字符串指針的任何嘗試都是危險的嘗試。以下安全地將 Unicode 字符串轉換為 ASCII(將`c_string_encoding`更改為`default`以使用默認編碼): ```py # cython: c_string_type=unicode, c_string_encoding=ascii def func(): ustring = u'abc' cdef char* s = ustring return s[0] # returns u'a' ``` (此示例使用函數上下文來安全地控制 Unicode 字符串的生命周期。可以從外部修改全局 Python 變量,這使得依賴其值的生命周期變得很危險。) ## 源代碼編碼 當字符串文字出現在代碼中時,源代碼編碼很重要。它確定 Cython 將在字節文字的 C 代碼中存儲的字節序列,以及在解析字節編碼的源文件時 Cython 為 unicode 文字構建的 Unicode 代碼點。在 [**PEP 263** ](https://www.python.org/dev/peps/pep-0263)之后,Cython 支持源文件編碼的顯式聲明。例如,將以下注釋放在`ISO-8859-15`(Latin-9)編碼源文件的頂部(進入第一行或第二行)需要在解析器中啟用`ISO-8859-15`解碼: ```py # -*- coding: ISO-8859-15 -*- ``` 當沒有提供明確的編碼聲明時,源代碼被解析為 UTF-8 編碼的文本,如 [**PEP 3120** ](https://www.python.org/dev/peps/pep-3120)所指定的。 [UTF-8](https://en.wikipedia.org/wiki/UTF-8) 是一種非常常見的編碼,可以表示整個 Unicode 字符集,并且與有效編碼的純 ASCII 編碼文本兼容。這使得它成為通常主要由 ASCII 字符組成的源代碼文件的非常好的選擇。 例如,將以下行放入 UTF-8 編碼的源文件中將打印`5`,因為 UTF-8 對雙字節序列`'\xc3\xb6'`中的字母`'?'`進行編碼: ```py print( len(b'abc?') ) ``` 而以下`ISO-8859-15`編碼的源文件將打印`4`,因為編碼僅使用此字母的 1 個字節: ```py # -*- coding: ISO-8859-15 -*- print( len(b'abc?') ) ``` 請注意,unicode 文字`u'abc?'`在兩種情況下都是正確解碼的四字符 Unicode 字符串,而未加前綴的 Python [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") 文字`'abc?'`將成為 Python 2 中的字節字符串(因此長度為 4)或者在上面的示例中為 5),以及 Python 3 中的 4 個字符的 Unicode 字符串。如果您不熟悉編碼,則在首次閱讀時可能看起來不太明顯。有關詳細信息,請參閱 [CEP 108](https://github.com/cython/cython/wiki/enhancements-stringliterals) 。 根據經驗,最好避免使用未加前綴的非 ASCII [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") 文字,并對所有文本使用 unicode 字符串文字。 Cython 還支持`__future__` import `unicode_literals`,它指示解析器將源文件中所有未加前綴的 [`str`](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.7)") 文字讀取為 unicode 字符串文字,就像 Python 3 一樣。 ## 單字節和字符 Python C-API 使用普通的 C `char`類型來表示字節值,但它有兩個特殊的整數類型用于 Unicode 代碼點值,即單個 Unicode 字符: [`Py_UNICODE`](https://docs.python.org/3/c-api/unicode.html#c.Py_UNICODE "(in Python v3.7)") 和 [`Py_UCS4`](https://docs.python.org/3/c-api/unicode.html#c.Py_UCS4 "(in Python v3.7)") 。 Cython 支持第一個本地,支持 [`Py_UCS4`](https://docs.python.org/3/c-api/unicode.html#c.Py_UCS4 "(in Python v3.7)") 是 Cython 0.15 的新功能。 [`Py_UNICODE`](https://docs.python.org/3/c-api/unicode.html#c.Py_UNICODE "(in Python v3.7)") 定義為無符號 2 字節或 4 字節整數,或定義為`wchar_t`,具體取決于平臺。確切類型是 CPython 解釋器構建中的編譯時選項,擴展模塊在 C 編譯時繼承此定義。 [`Py_UCS4`](https://docs.python.org/3/c-api/unicode.html#c.Py_UCS4 "(in Python v3.7)") 的優點在于,無論平臺如何,它都可以保證足夠大,以適應任何 Unicode 代碼點值。它被定義為 32 位無符號整數或長整數。 在 Cython 中,`char`類型在強制轉換為 Python 對象時與 [`Py_UNICODE`](https://docs.python.org/3/c-api/unicode.html#c.Py_UNICODE "(in Python v3.7)") 和 [`Py_UCS4`](https://docs.python.org/3/c-api/unicode.html#c.Py_UCS4 "(in Python v3.7)") 類型的行為不同。類似于 Python 3 中字節類型的行為,`char`類型默認強制為 Python 整數值,因此以下打印 65 而不是`A`: ```py # -*- coding: ASCII -*- cdef char char_val = 'A' assert char_val == 65 # ASCII encoded byte value of 'A' print( char_val ) ``` 如果你想要一個 Python 字節字符串,你必須明確地請求它,以下將打印`A`(或 Python 3 中的`b'A'`): ```py print( <bytes>char_val ) ``` 顯式強制適用于任何 C 整數類型。超出`char`或`unsigned char`范圍的值將在運行時升高 [`OverflowError`](https://docs.python.org/3/library/exceptions.html#OverflowError "(in Python v3.7)") 。在分配類型變量時,強制也會自動發生,例如: ```py cdef bytes py_byte_string py_byte_string = char_val ``` 另一方面, [`Py_UNICODE`](https://docs.python.org/3/c-api/unicode.html#c.Py_UNICODE "(in Python v3.7)") 和 [`Py_UCS4`](https://docs.python.org/3/c-api/unicode.html#c.Py_UCS4 "(in Python v3.7)") 類型很少在 Python unicode 字符串的上下文之外使用,因此它們的默認行為是強制使用 Python unicode 賓語。因此,以下將打印字符`A`,與 [`Py_UNICODE`](https://docs.python.org/3/c-api/unicode.html#c.Py_UNICODE "(in Python v3.7)") 類型的代碼相同: ```py cdef Py_UCS4 uchar_val = u'A' assert uchar_val == 65 # character point value of u'A' print( uchar_val ) ``` 同樣,顯式轉換將允許用戶覆蓋此行為。以下將打印 65: ```py cdef Py_UCS4 uchar_val = u'A' print( <long>uchar_val ) ``` 請注意,轉換為 C `long`(或`unsigned long`)將正常工作,因為 Unicode 字符可以具有的最大代碼點值是 1114111(`0x10FFFF`)。在 32 位或更高的平臺上,`int`同樣出色。 ## 窄 Unicode 構建 在版本 3.3 之前的 CPython 的窄版本構建中,即在`sys.maxunicode`為 65535 的情況下構建(例如所有 Windows 構建,而不是寬版本中的 1114111),仍然可以使用不適合的字符串代碼點。 16 位寬 [`Py_UNICODE`](https://docs.python.org/3/c-api/unicode.html#c.Py_UNICODE "(in Python v3.7)") 類型。例如,這樣的 CPython 構建將接受 unicode 文字`u'\U00012345'`。但是,在這種情況下,底層系統級編碼泄漏到 Python 空間中,因此該文字的長度變為 2 而不是 1.這也顯示在迭代它或索引到它時。在這個例子中,可見的子串是`u'\uD808'`和`u'\uDF45'`。它們形成了代表上述特征的所謂代理對。 有關該主題的更多信息,請閱讀 [Wikipedia 關于 UTF-16 編碼](https://en.wikipedia.org/wiki/UTF-16/UCS-2)的文章。 相同的屬性適用于為窄 CPython 運行時環境編譯的 Cython 代碼。在大多數情況下,例如在搜索子字符串時,可以忽略此差異,因為文本和子字符串都將包含代理項。因此,大多數 Unicode 處理代碼也可以在窄版本上正常工作。編碼,解碼和打印將按預期工作,因此上述文字在窄和寬 Unicode 平臺上變成完全相同的字節序列。 但是,程序員應該知道單個 [`Py_UNICODE`](https://docs.python.org/3/c-api/unicode.html#c.Py_UNICODE "(in Python v3.7)") 值(或 CPython 中的單個'字符'unicode 字符串)可能不足以在窄平臺上表示完整的 Unicode 字符。例如,如果在 unicode 字符串中對`u'\uD808'`和`u'\uDF45'`的獨立搜索成功,則這并不一定意味著字符`u'\U00012345`是該字符串的一部分。很可能是字符串中的兩個不同的字符碰巧與所討論的字符的代理對共享代碼單元。尋找子串正常工作是因為代理對中的兩個代碼單元使用不同的值范圍,因此該對在代碼點序列中始終是可識別的。 從版本 0.15 開始,Cython 擴展了對代理對的支持,因此即使在狹窄的平臺上,您也可以安全地使用`in`測試從完整的 [`Py_UCS4`](https://docs.python.org/3/c-api/unicode.html#c.Py_UCS4 "(in Python v3.7)") 范圍中搜索字符值: ```py cdef Py_UCS4 uchar = 0x12345 print( uchar in some_unicode_string ) ``` 類似地,它可以在窄和寬 Unicode 平臺上將具有高 Unicode 代碼點值的一個字符串強制轉換為 Py_UCS4 值: ```py cdef Py_UCS4 uchar = u'\U00012345' assert uchar == 0x12345 ``` 在 CPython 3.3 及更高版本中, [`Py_UNICODE`](https://docs.python.org/3/c-api/unicode.html#c.Py_UNICODE "(in Python v3.7)") 類型是系統特定`wchar_t`類型的別名,不再與 Unicode 字符串的內部表示相關聯。相反,任何 Unicode 字符都可以在所有平臺上表示,而無需使用代理項對。這意味著無論 [`Py_UNICODE`](https://docs.python.org/3/c-api/unicode.html#c.Py_UNICODE "(in Python v3.7)") 的大小如何,該版本都不再存在窄版本。有關詳細信息,請參閱 [**PEP 393** ](https://www.python.org/dev/peps/pep-0393)。 只要將類型推斷應用于無類型變量或者在源代碼中明確使用可移植 [`Py_UCS4`](https://docs.python.org/3/c-api/unicode.html#c.Py_UCS4 "(in Python v3.7)") 類型,Cython 0.16 及更高版本內部處理此更改并對單個字符值執行正確的操作平臺特異性 [`Py_UNICODE`](https://docs.python.org/3/c-api/unicode.html#c.Py_UNICODE "(in Python v3.7)") 型。 Cython 應用于 Python unicode 類型的優化將在 C 編譯時自動適應 [**PEP 393** ](https://www.python.org/dev/peps/pep-0393),像往常一樣。 ## 迭代 只要循環變量被適當地鍵入,Cython 0.13 就支持對`char*`,字節和 unicode 字符串的有效迭代。所以以下將生成預期的 C 代碼: ```py cdef char* c_string = "Hello to A C-string's world" cdef char c for c in c_string[:11]: if c == 'A': print("Found the letter A") ``` 這同樣適用于字節對象: ```py cdef bytes bytes_string = b"hello to A bytes' world" cdef char c for c in bytes_string: if c == 'A': print("Found the letter A") ``` 對于 unicode 對象,Cython 會自動將循環變量的類型推斷為 [`Py_UCS4`](https://docs.python.org/3/c-api/unicode.html#c.Py_UCS4 "(in Python v3.7)") : ```py cdef unicode ustring = u'Hello world' # NOTE: no typing required for 'uchar' ! for uchar in ustring: if uchar == u'A': print("Found the letter A") ``` 自動類型推斷通常會在這里產生更高效的代碼。但是,請注意,某些 unicode 操作仍然需要將值作為 Python 對象,因此 Cython 最終可能會為循環內部的循環變量值生成冗余轉換代碼。如果這導致特定代碼段的性能下降,您可以顯式地將循環變量鍵入為 Python 對象,或者將其值賦值給循環內部的 Python 類型變量,以在運行 Python 之前強制執行一次性強制對它的操作。 `in`測試也有優化,因此以下代碼將在純 C 代碼中運行(實際上使用 switch 語句): ```py cpdef void is_in(Py_UCS4 uchar_val): if uchar_val in u'abcABCxY': print("The character is in the string.") else: print("The character is not in the string") ``` 結合上面的循環優化,這可以產生非常有效的字符切換代碼,例如,在 unicode 解析器中。 ## Windows 和寬字符 API Windows 系統 API 本身以零終止 UTF-16 編碼`wchar_t*`字符串的形式支持 Unicode,因此稱為“寬字符串”。 默認情況下,Windows 版本的 CPython 定義 [`Py_UNICODE`](https://docs.python.org/3/c-api/unicode.html#c.Py_UNICODE "(in Python v3.7)") 作為`wchar_t`的同義詞。這使得內部`unicode`表示與 UTF-16 兼容,并允許有效的零拷貝轉換。這也意味著 Windows 構建總是[窄 Unicode 構建](#narrow-unicode-builds)與所有警告。 為了幫助與 Windows API 互操作,Cython 0.19 支持寬字符串(以`Py_UNICODE*`的形式)并隱式地將它們轉換為`unicode`字符串對象。這些轉換的行為與`char*`和 [`bytes`](https://docs.python.org/3/library/stdtypes.html#bytes "(in Python v3.7)") 相同,如[傳遞字節串](#passing-byte-strings)中所述。 除自動轉換外,C 語境中出現的 unicode 文字成為 C 級寬字符串文字, [`len()`](https://docs.python.org/3/library/functions.html#len "(in Python v3.7)") 內置函數專門用于計算零終止`Py_UNICODE*`字符串或數組的長度。 以下是如何在 Windows 上調用 Unicode API 的示例: ```py cdef extern from "Windows.h": ctypedef Py_UNICODE WCHAR ctypedef const WCHAR* LPCWSTR ctypedef void* HWND int MessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, int uType) title = u"Windows Interop Demo - Python %d.%d.%d" % sys.version_info[:3] MessageBoxW(NULL, u"Hello Cython \u263a", title, 0) ``` 警告 強烈建議不要在 Windows 之外使用`Py_UNICODE*`字符串。 [`Py_UNICODE`](https://docs.python.org/3/c-api/unicode.html#c.Py_UNICODE "(in Python v3.7)") 本身在不同平臺和 Python 版本之間不可移植。 CPython 3.3 已經轉移到 unicode 字符串( [**PEP 393** ](https://www.python.org/dev/peps/pep-0393))的靈活內部表示,使得所有 [`Py_UNICODE`](https://docs.python.org/3/c-api/unicode.html#c.Py_UNICODE "(in Python v3.7)") 相關 API 被棄用,效率低下。 CPython 3.3 更改的一個結果是`unicode`字符串的 [`len()`](https://docs.python.org/3/library/functions.html#len "(in Python v3.7)") 總是在 _ 代碼點 _(“字符”)中測量,而 Windows API 期望 UTF-16 的數量 _ 代碼單元 _(每個代理單獨計算)。要始終獲得代碼單元的數量,請直接調用 [`PyUnicode_GetSize()`](https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_GetSize "(in Python v3.7)") 。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看