Co dokładnie robią flagi ciągów „u” i „r” i jakie są dosłowne ciągi literalne?

652

Zadając to pytanie , zdałem sobie sprawę, że niewiele wiem o surowych ciągach. Dla kogoś, kto twierdzi, że jest trenerem Django, to jest do kitu.

Wiem, co to jest kodowanie i wiem, co u''robi sam, ponieważ dostaję kod Unicode.

  • Ale co r''dokładnie robi? Jaki to rodzaj ciągu?

  • A przede wszystkim, co do cholery robi ur''?

  • Wreszcie, czy istnieje jakiś niezawodny sposób na powrót z łańcucha Unicode do zwykłego łańcucha surowego?

  • Ach, a przy okazji, jeśli twój system i zestaw znaków edytora tekstowego są ustawione na UTF-8, to czy u''faktycznie coś robi?

e-satis
źródło

Odpowiedzi:

683

Tak naprawdę nie ma „surowego ciągu ”; istnieją surowe literały łańcuchowe , które są dokładnie literałami łańcuchowymi oznaczonymi 'r'przed cudzysłowiem otwierającym.

„Nieprzetworzony dosłowny ciąg znaków” to nieco inna składnia dla dosłownego ciągu znaków, w którym odwrotny ukośnik \jest traktowany jako „tylko odwrotny ukośnik” (z wyjątkiem sytuacji, gdy pojawia się tuż przed cytatem, który w przeciwnym razie zakończyłby dosłowność) - nie „sekwencje specjalne” reprezentujące znaki nowego wiersza, tabulatory, spacje, feed-form i tak dalej. W normalnych literałach łańcuchowych każdy odwrotny ukośnik musi zostać podwojony, aby uniknąć wzięcia go za początek sekwencji ucieczki.

Ten wariant składni istnieje głównie dlatego, że składnia wzorców wyrażeń regularnych jest obciążona odwrotnymi ukośnikami (ale nigdy na końcu, więc powyższa klauzula „oprócz” nie ma znaczenia) i wygląda nieco lepiej, gdy unikasz podwojenia każdego z nich - - to wszystko. Zyskał również pewną popularność do wyrażania natywnych ścieżek plików systemu Windows (z ukośnikami odwrotnymi zamiast zwykłych ukośników, takich jak na innych platformach), ale jest to bardzo rzadko potrzebne (ponieważ normalne ukośniki działają również dobrze w systemie Windows) i niedoskonałe (z powodu klauzuli „oprócz” powyżej).

r'...'jest ciągiem bajtów (w Pythonie 2. *) ur'...'jest ciągiem znaków Unicode (ponownie, w Pythonie 2. *), a każdy z pozostałych trzech rodzajów cytując produkuje także dokładnie te same rodzaje strun (tak na przykład r'...', r'''...''', r"...", r"""..."""są ciągami bajtów itd.).

Nie jestem pewien, co rozumiesz przez „ cofanie się ” - nie ma wewnętrznych wskazówek do przodu i do tyłu, ponieważ nie ma surowego typu łańcucha , jest to po prostu alternatywna składnia do wyrażania idealnie normalnych obiektów łańcucha, bajtów lub Unicode.

I tak, w Pythonie 2. *, u'...' jest oczywiście zawsze różni się od właśnie '...'- były to ciąg Unicode, ten ostatni jest ciągiem bajtów. To, co może być wyrażone w literale, jest kwestią całkowicie ortogonalną.

Np. Rozważ (Python 2.6):

>>> sys.getsizeof('ciao')
28
>>> sys.getsizeof(u'ciao')
34

Obiekt Unicode zajmuje oczywiście więcej miejsca w pamięci (oczywiście niewielka różnica w przypadku bardzo krótkiego łańcucha; oczywiście ;-).

Alex Martelli
źródło
6
Zrozumienie „r” nie oznacza żadnych problemów z typem ani kodowaniem, jest o wiele prostsze.
e-satis
23
Zauważ, że ru "C: \ foo \ unstable" nie powiedzie się, ponieważ \ u jest sekwencją ucieczkową Unicode w trybie ru. Tryb r nie ma \ u.
Curtis Yallop,
26
Zauważ, że ui rnie są przemienne: ur'str'działa, ru'str'nie. (przynajmniej w ipython 2.7.2 na win7)
RafiK
7
Właśnie przetestowałem rciągi i zauważyłem, że jeśli \ jest ostatnim znakiem, nie będzie traktowany jako dosłowny, ale zamiast tego wymyka się cudzysłowowi, powodując SyntaxError: EOL while scanning string literal. Tak więc \\ nadal musi być użyty do ostatniej instancji \ dowolnego łańcucha zakończonego odwrotnym ukośnikiem.
Enteleform
1
python 3.x - sys.getsizeof('cioa') == sys.getsizeof(r'cioa') == sys.getsizeof(u'cioa')(Ubuntu 16.04 z językiem UTF8). Podobnie type('cioa') == type(r'cioa') == type(u'cioa'). ALE interpolacja łańcuchów surowych robi różnicę, więcsys.getsizeof('\ncioa') == sys.getsizeof(u'\ncioa') != sys.getsizeof(r'\ncioa')
Darren Weber
177

W Pythonie istnieją dwa typy ciągów: tradycyjny stri nowszy unicode. Jeśli wpiszesz literał ciąg bez znaku z uprzodu, otrzymasz stary strtyp, który przechowuje znaki 8-bitowe, a z uprzodu otrzymasz nowszy unicodetyp, który może przechowywać dowolny znak Unicode.

W rogóle nie zmienia typu, zmienia jedynie interpretację literału łańcuchowego. Bez rukośników odwrotnych są traktowane jako znaki specjalne. Z rodwrotnymi ukośnikami są traktowane jako dosłowne. Tak czy inaczej, typ jest taki sam.

ur jest oczywiście łańcuchem Unicode, w którym odwrotne ukośniki są dosłowne odwrotnymi ukośnikami, a nie częścią kodów specjalnych.

Możesz spróbować przekonwertować ciąg Unicode na stary, używając tej str()funkcji, ale jeśli istnieją znaki Unicode, których nie można reprezentować w starym ciągu, otrzymasz wyjątek. Jeśli chcesz, możesz najpierw zastąpić je znakami zapytania, ale oczywiście spowoduje to, że te postacie będą nieczytelne. Nie zaleca się używania tego strtypu, jeśli chcesz poprawnie obsługiwać znaki Unicode.

Mark Byers
źródło
Dziękuję, zaakceptowano. Jak powiedziałem, rozumiem, co to jest unicode, nie wiedziałem, co oznacza „r” i jaka byłaby kombinacja „u” i „r”. Wiem, lepiej wiem, na zdrowie.
e-satis,
6
Ukośniki odwrotne nie są traktowane jako literały w literałach nieprzetworzonych, dlatego r"\"występuje błąd składniowy.
4
Dotyczy tylko Python 2.
PaulMcG,
60

„nieprzetworzony ciąg” oznacza, że ​​jest przechowywany tak, jak się wydaje. Na przykład '\'jest tylko odwrotnym ukośnikiem zamiast ucieczki .

Xiaolong
źródło
3
... chyba że jest to ostatni znak ciągu, w którym to przypadku unika zamykającego cudzysłowu.
jez
36

Prefiks „u” oznacza, że ​​wartość ma typ, unicodea nie typ str.

Nieprzetworzone literały łańcuchowe z prefiksem „r” unikają wszelkich zawartych w nich sekwencji ucieczki, podobnie jak len(r"\n")2. Ponieważ są to sekwencje specjalne, nie można kończyć literału łańcucha pojedynczym odwrotnym ukośnikiem: to nie jest poprawna sekwencja Escape (np r"\".).

„Surowe” nie jest częścią tego typu, jest tylko jednym ze sposobów przedstawienia wartości. Na przykład, "\\n"i r"\n"są identyczne wartości, podobnie jak 32, 0x20i 0b100000są identyczne.

Możesz mieć nieprzetworzone dosłowne ciągi literałów:

>>> u = ur"\n"
>>> print type(u), len(u)
<type 'unicode'> 2

Kodowanie pliku źródłowego określa tylko sposób interpretacji pliku źródłowego, nie wpływa to w żaden sposób na wyrażenia ani typy. Jednakże, jest to zalecane , aby uniknąć kod gdzie kodowanie inne niż ASCII zmieniłoby znaczenie:

Pliki korzystające z ASCII (lub UTF-8, dla Python 3.0) nie powinny mieć kodującego pliku cookie. Latin-1 (lub UTF-8) należy stosować tylko wtedy, gdy komentarz lub dokument wymaga podania nazwiska autora wymagającego Latin-1; w przeciwnym razie użycie znaków ucieczki \ x, \ u lub \ U jest preferowanym sposobem włączenia danych spoza ASCII do literałów łańcuchowych.


źródło
30

Pozwól, że wyjaśnię to po prostu: w Pythonie 2 możesz przechowywać ciąg znaków w 2 różnych typach.

Pierwszym z nich jest ASCII, który jest typu str w pythonie, wykorzystuje 1 bajt pamięci. (256 znaków, będzie przechowywać głównie angielskie alfabety i proste symbole)

Drugi typ to UNICODE, który jest typem Unicode w python. Unicode przechowuje wszystkie typy języków.

Domyślnie Python preferuje typ str, ale jeśli chcesz przechowywać ciąg w typie Unicode , możesz umieścić u przed tekstem, np. U'text, lub możesz to zrobić, wywołując Unicode („tekst”)

Więc u jest tylko krótki sposób, aby wywołać funkcję, aby rzutować str na Unicode . Otóż ​​to!

Teraz część r , umieszczasz przed tekstem, aby poinformować komputer, że tekst jest tekstem surowym, ukośnik odwrotny nie powinien być znakiem ucieczki. r '\ n' nie utworzy nowego znaku linii. To tylko zwykły tekst zawierający 2 znaki.

Jeśli chcesz przekonwertować str na Unicode, a także wstawić tam nieprzetworzony tekst, użyj ur, ponieważ ru spowoduje błąd.

TERAZ ważna część:

Nie można zapisać jednego ukośnika odwrotnego za pomocą r , to jedyny wyjątek. Więc ten kod spowoduje błąd: r '\'

Aby zapisać ukośnik odwrotny (tylko jeden), musisz użyć „\\”

Jeśli chcesz przechowywać więcej niż 1 znaków można nadal korzystać z R jak r „\\” będzie produkować 2 backslashy jak oczekiwano.

Nie znam powodu, dla którego r nie działa z jednym magazynem ukośnika odwrotnego, ale powód nie jest jeszcze opisany przez nikogo. Mam nadzieję, że to błąd.

off99555
źródło
9
Zauważysz, że nie tylko r'\'jest to nielegalne, nie możesz nawet postawić ani jednego '\'ogona. Podobnie jak r'xxxxxx\'nielegalny ciąg.
rozbieżny
co z python 3?
Krissh,
1
@ Krissh Wszystkie ciągi Pythona 3 są obsługiwane w standardzie Unicode. Będzie to typ str. Przeczytaj więcej dla lepszego zrozumienia tutaj: medium.com/better-programming/…
off99555 10.0919
4

Może to oczywiste, może nie, ale możesz zrobić ciąg „\” , wywołując x = chr (92)

x=chr(92)
print type(x), len(x) # <type 'str'> 1
y='\\'
print type(y), len(y) # <type 'str'> 1
x==y   # True
x is y # False
Bomba Ps
źródło
4
x is yocenia na True w python3?
Habeeb Perwad
5
@HabeebPerwad, to jest z powodu internowania łańcucha . Nigdy nie powinieneś polegać na fakcie, że x is ytak się dzieje Truez internowaniem. Zamiast tego użyj x == y(jeśli nie sprawdzasz, czy xiy są dokładnie tym samym obiektem przechowywanym w jednej pozycji pamięci, to znaczy).
Lucubrator,
4

Literały łańcuchowe Unicode

Literały ciągów Unicode (literały ciągów z prefiksem u) niejuż używane w Pythonie 3. Są one nadal aktualne, ale wyłącznie w celu zachowania zgodności z Pythonem 2.

Surowe literały łańcuchowe

Jeśli chcesz utworzyć ciąg składający się tylko z literalną łatwo oznaczalnych izolatów znaków takich jak angielskich liter lub cyfr, można po prostu wpisać je: 'hello world'. Ale jeśli chcesz dołączyć także bardziej egzotyczne postacie, musisz użyć obejścia. Jednym z obejść są sekwencje specjalne . W ten sposób możesz na przykład reprezentować nowy wiersz w łańcuchu, po prostu dodając dwa łatwe do wpisania znaki \ndo literału łańcucha. Kiedy więc wydrukujesz 'hello\nworld'ciąg, słowa zostaną wydrukowane w osobnych wierszach. To bardzo przydatne!

Z drugiej strony istnieją sytuacje, w których chcesz utworzyć literał łańcuchowy zawierający sekwencje specjalne, ale nie chcesz, aby były one interpretowane przez Python. Chcesz, żeby były surowe . Spójrz na te przykłady:

'New updates are ready in c:\windows\updates\new'
'In this lesson we will learn what the \n escape sequence does.'

W takich sytuacjach możesz po prostu poprzedzić literał ciągiem rznakiem takim jak ten: r'hello\nworld'i żadne sekwencje specjalne nie będą interpretowane przez Python. Ciąg zostanie wydrukowany dokładnie tak, jak go utworzyłeś.

Surowe literały łańcuchowe nie są całkowicie „surowe”?

Wiele osób oczekuje, że surowe literały łańcuchowe będą surowe w tym sensie, że „wszystko umieszczone między cudzysłowami jest ignorowane przez Python” . To nie jest prawda. Python nadal rozpoznaje wszystkie sekwencje specjalne, po prostu ich nie interpretuje - zamiast tego pozostawia je niezmienione. Oznacza to, że nieprzetworzone literały łańcuchowe wciąż muszą być poprawnymi literałami łańcuchowymi .

Z leksykalnej definicji literału łańcuchowego:

string     ::=  "'" stringitem* "'"
stringitem ::=  stringchar | escapeseq
stringchar ::=  <any source character except "\" or newline or the quote>
escapeseq  ::=  "\" <any source character>

Oczywiste jest, że literały łańcuchowe (nieprzetworzone lub nie) zawierające czysty znak cudzysłowu: 'hello'world'lub kończące się odwrotnym ukośnikiem: 'hello world\'są nieprawidłowe.

Jeyekomon
źródło