2009-03-15 9 views
113

Technicznie, nieparzysta liczba ukośników odwrotnych, jak opisano w the docs.Dlaczego literały łańcucha znaków Pythona nie mogą kończyć się pojedynczym ukośnikiem odwrotnym?

>>> r'\' 
    File "<stdin>", line 1 
    r'\' 
    ^
SyntaxError: EOL while scanning string literal 
>>> r'\\' 
'\\\\' 
>>> r'\\\' 
    File "<stdin>", line 1 
    r'\\\' 
     ^
SyntaxError: EOL while scanning string literal 

Wydaje się, że parser może po prostu traktować backslashy surowca ciągi jako zwykłe znaki (nie jest to, co surowe ciągi są wszystkim chodzi?), Ale jestem prawdopodobnie brakuje coś oczywistego. TIA!

+7

wygląda to teraz [FAQ] (http://docs.python.org/faq/design.html#why-can-t-raw-strings-r-strings-end-with-a -ukośnik wsteczny). być może nie było, gdy zadałeś pytanie.Wiem, że dokumenty, które cytowałeś, mówią w zasadzie to samo, ale pomyślałem, że dodam kolejne źródło dokumentacji. – oob

Odpowiedz

88

Powodem jest wyjaśnione w części tej sekcji której zaznacza się wytłuszczonym drukiem:

cytaty String można uciec z backslash, ale odwrotny ukośnik pozostaje w ciągu; na przykład: r"\"" jest ważnym ciągiem literowym składającym się z dwóch znaków : odwrotnego ukośnika i podwójnego cytatu ; r"\" nie jest prawidłowym łańcuchem literał (nawet surowy ciąg znaków nie może kończyć się w nieparzystej liczbie ukośników odwrotnych). W szczególności nieprzetworzony ciąg znaków nie może kończyć się w jednym odwróconym ukośniku odwrotnym (ponieważ odwrotny ukośnik wymknie się z następującej cytowanej litery ). Zauważ również, że pojedynczy ukośnik odwrotny, a następnie znak nowej linii jest interpretowany jako dwa znaki jako część ciągu, a nie jako kontynuacja linii.

Tak surowe struny nie są w 100% nieprzetworzone, wciąż istnieje pewne podstawowe przetwarzanie odwróconego ukośnika.

+10

Och, wow ... to dziwne. Dobry chwyt. Ma sens, że r '\' '== "\\" ", ale wciąż jest dziwne, że postać ucieczki ma efekt bez znikania. – cdleary

+0

Równie dobrze możesz użyć ukośnika w przód, aby osiągnąć ten sam cel. To działało w systemie Windows 7 Python 2.7 ... root_path = r'P:/Temp/IT/', a następnie użyj go do utworzenia podfolderu w ten sposób: create_folder = root_path + sub_folder – ihightower

+1

@ihightower może to działać dla ścieżek systemu plików, ale istnieją inne zastosowania odwrotnego ukośnika. W przypadku ścieżek systemu plików nie koduj separatora. Użyj "os.path.sep", lub lepiej funkcji wyższego poziomu "os.path". (Lub "pathlib", jeśli jest dostępny) – oefe

2

Powodem, dla którego r'\' jest niepoprawny pod względem składni jest to, że chociaż wyrażenie tekstowe jest nieprzetworzone, używane cudzysłowy (pojedyncze lub podwójne) zawsze muszą być uciec, ponieważ oznaczałyby koniec cytatu w inny sposób. Więc jeśli chcesz wyrazić pojedynczy cudzysłów wewnątrz pojedynczego cudzysłowu, nie ma innego sposobu niż użycie \'. To samo dotyczy podwójnych ofert.

Ale można użyć:

'\\' 
+1

Nie odpowiada "dlaczego" :-) – cdleary

17

Tak to już jest! Widzę to jako jedną z tych małych wad w pytonie!

Nie sądzę, że istnieje ku temu dobry powód, ale zdecydowanie nie analizuje; bardzo łatwo jest parsować nieprzetworzone ciągi z \ jako ostatnią postacią.

Połów jest, jeśli zezwalasz na \ być ostatnim znakiem w surowym łańcuchu, wtedy nie będziesz w stanie umieścić "wewnątrz surowego łańcucha." Wygląda na to, że python poszedł z zezwoleniem "zamiast pozwolić \ jako ostatnim postać.

Jednak nie powinno to powodować żadnych problemów.

Jeśli martwisz się o nie jest w stanie łatwo napisać folderze Windows Ścieżki edukacyjne takie jak c:\mypath\ potem nie martwić, bo można ich reprezentować jako r"C:\mypath", a jeśli trzeba dołączyć nazwę podkatalogu, nie rób to z łączeniem ciągów, bo i tak nie jest to właściwe!używać os.path.join

>>> import os 
>>> os.path.join(r"C:\mypath", "subfolder") 
'C:\\mypath\\subfolder' 
+2

Dobry materiał pomocniczy. :-) Adwokat diabła, chociaż: czasami chcesz odróżnić ścieżki plików od ścieżek katalogów przez dołączenie separatora ścieżek. Ciekawą rzeczą w os.path.join jest to, że je zwiną: assert os.path.join ('/ home/cdleary /', 'foo /', 'bar /') == '/ home/cdleary/foo/bar/' – cdleary

+0

Nie powoduje to jednak (technicznej) różnicy! os.path.isdir powie ci, czy dana ścieżka jest katalogiem (folderem). – hasen

+1

Tak, to po prostu wskazanie komuś czytającemu kod, czy spodziewasz się, że ścieżka będzie katalogiem czy plikiem. – cdleary

1

Inny użytkownik, który został usunięty, ponieważ ich odpowiedź (nie wiem, czy chcieliby zostać przelana) zasugerował, że projektanci języka Python może być w stanie uprościć projektowanie parsera przy użyciu tych samych zasad i analizowania rozszerzenie znaków z ewakuacji do postaci surowej jako refleksji (jeśli literał został oznaczony jako nieprzetworzony).

Pomyślałem, że to ciekawy pomysł i dołączam go do społeczności jako wiki dla potomności.

+0

parsowanie jest łatwe w obie strony. – hasen

+0

Ale może ci to pozwolić uniknąć dwóch oddzielnych ścieżek kodu ścieżki-literału-parsera. – cdleary

7

Od \ „jest dozwolone wewnątrz surowego ciąg. Wtedy nie może być stosowany do identyfikacji koniec łańcucha dosłowne.

Dlaczego nie zatrzymać parsowania ciąg dosłowny, gdy napotkasz pierwszy”?

Jeśli tak było, to \”nie wolno wewnątrz łańcucha dosłownym. Ale to jest.

+1

Dokładnie. Projektanci Pythona prawdopodobnie ocenili prawdopodobieństwo dwóch alternatyw: dwu-znakowej sekwencji '\" w dowolnym miejscu wewnątrz podwójnie cytowanego nieprzetworzonego ciągu, OR \ na końcu podwójnie cytowanego nieprzetworzonego łańcucha. Statystyki użycia muszą faworyzować dwie sekwencje znaków w dowolnym miejscu vs jednoliterowa sekwencja na końcu – hobs

0

Comming z C to całkiem dla mnie jasne, że pojedynczy \ pracuje jako znak anulowania co pozwala na umieść znaki specjalne, takie jak znaki nowej linii, tabulatory i cudzysłowy w łańcuchach znaków:

To faktycznie uniemożliwia \ jako ostatnią postać, ponieważ ucieknie przed "i sprawi, że parser się zadławił. Ale jak wskazano wcześniej \ jest legalne.

+1

Tak, sednem problemu było to, że surowe ciągi traktują \ jako dosłowne zamiast początkowej sekwencji ucieczki. Dziwne jest to, że wciąż ma właściwości ucieczki do cytowania , pomimo tego, że traktuje się je jak literalną postać: – cdleary

-1

kilka wskazówek:

1) Jeśli trzeba manipulować backslash na ścieżce następnie standardowy moduł python os.path jest twoim przyjacielem. na przykład:

os.path.normpath ('c:/folder1 /')

2) Jeśli chcesz zbudować ciągi ukośnik w to, ale bez backslash na końcu łańcucha następnie surowy ciąg jest twoim przyjacielem (przed swoim literalnym ciągiem użyj przedrostka "r"). na przykład:

r'\one \two \three' 

3) jeśli trzeba poprzedzić ciąg w zmiennej X z backslashem następnie można to zrobić:

X='dummy' 
bs=r'\ ' # don't forget the space after backslash or you will get EOL error 
X2=bs[0]+X # X2 now contains \dummy 

4) Jeżeli trzeba utworzyć ciąg z ukośnikowe na końcu następnie połączyć końcówkę 2 i 3:

voice_name='upper' 
lilypond_display=r'\DisplayLilyMusic \ ' # don't forget the space at the end 
lilypond_statement=lilypond_display[:-1]+voice_name 

teraz lilypond_statement zawiera "\DisplayLilyMusic \upper"

długo żywy pyton! :)

n3on

+1

Żadne z nich nie odpowiada na pytanie "dlaczego", ale nie należy używać # 3 i #. Cięcie i dodawanie ciągów jest ogólnie złą praktyką i powinieneś preferować r '\ dummy' dla # 3 (który działa dobrze) i ".join ([r '\ DisplayLilyMusic', r '\ upper']) do # 4. – cdleary

+1

Powód jest taki, że ciągi są niezmienne, a każdy plaster/konkatenacja tworzy nowy niezmienny obiekt typu string to jest zwykle odrzucenie ed. Lepiej zebrać je wszystkie i połączyć je w jednym kroku ze str.join (komponenty) – cdleary

+0

Och, whoops - źle zrozumiano, co miałeś na myśli # 3. Myślę, że prosty "\\" + X jest preferowany do tworzenia łańcucha tylko po to, by go pokroić. – cdleary

8

W celu, aby zakończyć surowy ciąg znaków z ukośnikiem proponuję można użyć tej sztuczki:

>>> print r"c:\test"'\\' 
test\ 
12

Inną sztuczką jest użycie Chr (92), jak to ocenia do "\".

Niedawno miałem do czyszczenia ciąg ukośniki i dodaje wystarczyły:

CleanString = DirtyString.replace(chr(92),'') 

Zdaję sobie sprawę, że to nie dbać o „dlaczego”, ale wątek przyciąga wielu ludzi szuka rozwiązania do natychmiastowego problemu.

+0

Ale co jeśli oryginalny ciąg zawiera ukośniki odwrotne? –

37

Całe błędne przekonanie na temat surowych ciągów Pythona jest takie, że większość ludzi uważa, że ​​ukośnik odwrotny (w surowym ciągu znaków) jest po prostu zwykłą postacią, tak jak wszystkie inne. Nie jest. Kluczem do zrozumienia jest sekwencja tego Python Tutorial:

Kiedy „r” lub „R” przedrostek jest obecny, postać następstwie backslash jest wliczone w ciągu bez zmian, a wszystkie backslashe są pozostawione w ciągu

Więc każdy znak po ukośnika jest część surowca sznurka. Gdy parser wprowadzi surowy łańcuch (bez znaku unicode) i napotka ukośnik odwrotny, wie, że są 2 znaki (ukośnik odwrotny i znak po nim).

następujący sposób:

r'abc \ d” zawiera a, b, c, \, d

r'abc \ 'd' zawiera a, b, c, \, 'd

r'abc \ '' zawiera a, b, c, \'

oraz:

r'abc \ ' zawiera a, b, c, \' ale nie kończący się cytat.

Ostatni przypadek pokazuje, że zgodnie z dokumentacją teraz parser nie może znaleźć końcowej wyceny, ponieważ ostatnia część, którą widzisz powyżej, jest częścią ciągu, tj. ukośnik odwrócony nie może być tu ostatni, ponieważ będzie "pochłaniał" łańcuch zamykający znak.

+2

To jest rzeczywiście bardziej przejrzyste niż zaakceptowana odpowiedź. Niezły awaria. –

+2

Ja również uważam to za znacznie jaśniejsze niż przyjęta odpowiedź, a także jestem fizykiem – xdavidliu

0

Pomimo swojej roli, a nawet surowy ciąg nie może kończyć się jeden ukośnik, być- spowodować odwrotny ukośnik ucieka Poniższy cytat character-ty nadal musi uciec otaczający znak cudzysłowu, aby osadzić go w ciągu . Oznacza to, że r "... \" nie jest poprawnym dosłownym ciągiem znaków - nieprzetworzony łańcuch nie może kończyć się nieparzystą liczbą odwróconych ukośników. Jeśli chcesz zakończyć surowy ciąg znaków za pomocą pojedynczego ukośnika odwrotnego, możesz użyć dwóch i odciąć sekundę sekund.

Powiązane problemy