Что именно делают строковые флаги «u» и «r», и что такое необработанные строковые литералы?

652

Задавая этот вопрос , я понял, что мало что знаю о необработанных строках. Для кого-то, претендующего на звание тренера Джанго, это отстой.

Я знаю, что такое кодировка, и я знаю, что u''делает одна, поскольку я получаю Unicode.

  • Но что именно делает r''? К какой строке это приводит?

  • И прежде всего, что, черт возьми, делает ur''?

  • Наконец, есть ли надежный способ вернуться от строки Unicode к простой необработанной строке?

  • Да, и, кстати, если ваша система и ваш кодировщик текстового редактора настроены на UTF-8, u''действительно что-нибудь делает?

е-удовлетворяться
источник

Ответы:

683

На самом деле нет никакой «необработанной строки »; есть необработанные строковые литералы , которые в точности являются строковыми литералами, помеченными 'r'перед открывающей кавычкой.

«Необработанный строковый литерал» - это немного другой синтаксис для строкового литерала, в котором обратный слеш \рассматривается как означающий «просто обратный слеш» (за исключением случаев, когда он идет прямо перед кавычкой, которая в противном случае завершила бы литерал) - нет «escape-последовательности» для представления новых строк, вкладок, обратных символов, каналов и т. д. В обычных строковых литералах каждый обратный слеш должен быть удвоен, чтобы его не принимали за начало escape-последовательности.

Этот вариант синтаксиса существует главным образом потому, что синтаксис шаблонов регулярных выражений насыщен обратными слешами (но никогда не заканчивается, поэтому вышеприведенное предложение «исключая» не имеет значения) и выглядит немного лучше, когда вы не удваиваете каждый из них - - это все. Он также приобрел некоторую популярность для выражения собственных путей к файлам Windows (с обратными слешами вместо обычных слешей, как на других платформах), но это очень редко необходимо (так как нормальные слэши в основном работают также и в Windows) и несовершенным (из-за предложения «кроме» над).

r'...'является байт строки (в Python 2. *), ur'...'это строка Unicode (опять же , в Python 2. *), и любой из трех других видов процитировать также производит одни и те же типы строк (так, например r'...', r'''...''', r"...", r"""..."""все байтовые строки и т. д.).

Не уверен, что вы имеете в виду под « возвращением » - нет внутренних указаний назад и вперед, потому что нет необработанного строкового типа , это просто альтернативный синтаксис для выражения совершенно обычных строковых объектов, байтов или юникодов, какими они могут быть.

И да, в Python 2. *, u'...' это , конечно , всегда отличается от всего '...'- бывший является строкой Юникода, последняя строка байт. В чем может быть выражена кодировка литерала - это совершенно ортогональный вопрос.

Например, рассмотрим (Python 2.6):

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

Разумеется, объект Unicode занимает больше места в памяти (очевидно, очень небольшая разница для очень короткой строки ;-).

Алекс Мартелли
источник
6
Понимание «r» не подразумевает проблем с типом или кодированием, оно намного проще.
E-удовлетворительно
23
Обратите внимание, что ru "C: \ foo \ unstable" завершится ошибкой, потому что \ u является escape-последовательностью Юникода в режиме ru. Режим r не имеет \ u.
Кертис Яллоп
26
Обратите внимание, что uи rне являются коммутативными:ur'str' работает, нет ru'str'. (по крайней мере, в ipython 2.7.2 на win7)
RafiK
7
Просто протестировал rстроки и заметил, что если \ это последний символ, он не будет восприниматься как литерал, а вместо этого будет выходить из закрывающей кавычки, вызывая SyntaxError: EOL while scanning string literal. Так что \\ еще нужно использовать для окончательного экземпляра\ в любых строках, заканчивающихся обратной косой чертой.
Enteleform
1
Python 3.x - sys.getsizeof('cioa') == sys.getsizeof(r'cioa') == sys.getsizeof(u'cioa')(Ubuntu 16.04 с UTF8 lang). Точно так же type('cioa') == type(r'cioa') == type(u'cioa'). НО, интерполяция необработанных строк имеет значение, поэтомуsys.getsizeof('\ncioa') == sys.getsizeof(u'\ncioa') != sys.getsizeof(r'\ncioa')
Даррен Вебер
177

В Python есть два типа строк: традиционный strтип и новый unicodeтип. Если вы вводите строковый литерал без uспереди, вы получаете старый strтип, который хранит 8-битные символы, а с uпередним вы получаете более новый unicodeтип, который может хранить любой символ Unicode.

Тип rвообще не меняет тип, он просто меняет интерпретацию строкового литерала. Без rобратного слеша они рассматриваются как escape-символы. При этом rобратные слеши рассматриваются как буквальные. В любом случае, тип один и тот же.

ur это, конечно, строка Unicode, где обратные косые черты являются буквальными обратными косыми чертами, а не частью escape-кодов.

Вы можете попытаться преобразовать строку Unicode в старую строку, используя str()функцию, но если есть какие-либо символы Unicode, которые не могут быть представлены в старой строке, вы получите исключение. Вы можете заменить их сначала вопросительными знаками, если хотите, но, конечно, это приведет к тому, что эти символы станут нечитаемыми. Не рекомендуется использовать strтип, если вы хотите правильно обрабатывать символы Юникода.

Марк Байерс
источник
Спасибо, приняли. Как я уже сказал, я знаю, что такое юникод, я не знал, что означает «r» и какова будет комбинация «u» и «r». Я знаю, лучше знаю, ура.
E-удовлетворительно
6
Обратные слеши не обрабатываются как литералы в необработанных строковых литералах, поэтому r"\"синтаксическая ошибка.
4
Относится только к Python 2.
PaulMcG
60

«Необработанная строка» означает, что она хранится в том виде, в котором она появилась. Например, '\'это просто обратная косая черта вместо побега .

Xiaolong
источник
3
... если это не последний символ строки, в этом случае он закрывает кавычку.
Еж
36

Префикс «u» обозначает, что значение имеет тип, unicodeа не str.

Необработанные строковые литералы с префиксом «r» экранируют любые escape-последовательности внутри них, len(r"\n")равно как и 2. Поскольку они экранируют escape-последовательности, вы не можете завершить строковый литерал одной обратной косой чертой: это недопустимая escape-последовательность (например r"\").

«Raw» не является частью типа, это просто один из способов представления значения. Например, "\\n"и r"\n"идентичны значения, точно так же, как 32и 0x20, и 0b100000идентичны.

У вас могут быть строковые литералы Unicode:

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

Кодировка исходного файла просто определяет, как интерпретировать исходный файл, иначе не влияет на выражения или типы. Тем не менее, рекомендуется избегать кода, где кодировка, отличная от ASCII, изменит значение:

Файлы, использующие ASCII (или UTF-8 для Python 3.0), не должны иметь файл cookie для кодирования. Latin-1 (или UTF-8) следует использовать только тогда, когда в комментарии или строке документации необходимо указать имя автора, для которого требуется Latin-1; в противном случае использование \ x, \ u или \ U escape-символов является предпочтительным способом включения не-ASCII-данных в строковые литералы.


источник
30

Позвольте мне объяснить это просто: в Python 2 вы можете хранить строки в 2 разных типах.

Первый - ASCII, который является типом str в python, он использует 1 байт памяти. (256 символов, будет хранить в основном английские алфавиты и простые символы)

Второй тип - это UNICODE, который является типом Unicode в Python. Unicode хранит все типы языков.

По умолчанию python предпочитает тип str, но если вы хотите сохранить строку в типе Unicode, вы можете поместить u перед текстом, как u'text ', или вы можете сделать это, вызвав unicode (' text ')

Так что у вас просто короткий способ вызвать функцию для приведения str к юникоду . Это оно!

Теперь г часть, вы ставите его перед текстом , чтобы сообщить компьютеру , что текст сырой текст, обратная косая черта не должен быть символом экранирования. r '\ n' не будет создавать символ новой строки. Это просто текст, содержащий 2 символа.

Если вы хотите преобразовать str в unicode, а также поместить туда необработанный текст, используйте ur, потому что ru вызовет ошибку.

СЕЙЧАС важная часть:

Вы не можете сохранить одну обратную косую черту, используя r , это единственное исключение. Так что этот код выдаст ошибку: r '\'

Чтобы сохранить обратную косую черту (только одну), вам нужно использовать '\\'

Если вы хотите сохранить более 1 символа, вы все равно можете использовать r, например, r '\\' произведет 2 обратных слеша, как вы и ожидали.

Я не знаю причину, по которой r не работает с одним хранилищем с обратной косой чертой, но причина еще никому не описана. Я надеюсь, что это ошибка.

off99555
источник
9
Вы заметите, что это не только r'\'незаконно, вы даже не можете поставить сингл '\'в хвост любой строки. Так же, как r'xxxxxx\'это незаконная строка.
Дивергер
а как насчет питона 3?
Крисс
1
@Krissh Все строки Python 3 поддерживаются Unicode. Тип его будет str. Подробнее для лучшего понимания здесь: medium.com/better-programming/...
off99555
4

Может быть, это очевидно, а может и нет, но вы можете сделать строку '\' , вызвав 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
Бомба Пс
источник
4
x is yоценивает True в python3?
Хабиб Perwad
5
@HabeebPerwad, это из-за интернирования строк . Вы никогда не должны полагаться на тот факт, что x is yпроисходит, чтобы оценить Trueиз-за интернирования. Вместо этого используйте x == y(если вы не проверяете, являются ли x и y одним и тем же объектом, хранящимся в одной позиции памяти, то есть).
Lucubrator
4

Строковые литералы Юникода

Строковые литералы Unicode (строковые литералы с префиксом u) больше не используются в Python 3. Они по-прежнему действительны, но только в целях совместимости с Python 2.

Необработанные строковые литералы

Если вы хотите создать строковый литерал , состоящий только легко типизируемого символы , такие как английские буквы или цифры, вы можете просто ввести их: 'hello world'. Но если вы хотите включить еще несколько экзотических персонажей, вам придется использовать обходной путь. Одним из обходных путей являются Escape-последовательности . Таким образом, вы можете, например, представить новую строку в вашей строке, просто добавив два легко набираемых символа \nв ваш строковый литерал. Поэтому, когда вы печатаете 'hello\nworld'строку, слова будут напечатаны в отдельных строках. Это очень удобно!

С другой стороны, в некоторых ситуациях вы хотите создать строковый литерал, содержащий escape-последовательности, но не хотите, чтобы они интерпретировались Python. Вы хотите, чтобы они были сырыми . Посмотрите на эти примеры:

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

В таких ситуациях вы можете просто поставить префикс строкового литерала следующим rсимволом: r'hello\nworld'Python не будет интерпретировать escape-последовательности. Строка будет напечатана именно так, как вы ее создали.

Необработанные строковые литералы не являются полностью «необработанными»?

Многие люди ожидают, что необработанные строковые литералы будут необработанными в том смысле, что «все, что находится между кавычками, игнорируется Python» . Это неправда. Python по-прежнему распознает все escape-последовательности, он просто не интерпретирует их - вместо этого он оставляет их без изменений. Это означает, что необработанные строковые литералы все еще должны быть допустимыми строковыми литералами .

Из лексического определения строкового литерала:

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

Ясно, что строковые литералы (необработанные или нет), содержащие символ пустой кавычки: 'hello'world'или заканчивающиеся обратной косой чертой: 'hello world\'недопустимы.

Jeyekomon
источник