Spec-Zone.ru › Julia 0.5

Строки

Строки — это конечные последовательности символов. Конечно, настоящая проблема возникает, когда задаётся вопрос о том, что такое символ. Символы, с которыми знакомы носители английского языка, — это буквы A, B, C, и т. д., вместе с цифрами и общими знаками препинания. Эти символы стандартизованы вместе с сопоставлением целочисленным значениям от 0 до 127 в стандарте ASCII. Конечно, существуют и многие другие символы, используемые в языках, отличных от английского, включая варианты символов ASCII с акцентами и другими модификациями, родственные алфавиты, такие как кириллица и греческий, и алфавиты, совершенно не связанные с ASCII и английским, включая арабский, китайский, иврит, хинди, японский и корейский. Стандарт Unicode решает сложности, связанные с тем, что такое символ, и в целом признан окончательным стандартом, решающим эту проблему. В зависимости от ваших потребностей, вы можете либо полностью игнорировать эти сложности и просто предположить, что существуют только символы ASCII, либо написать код, который может обрабатывать любые символы или кодировки, с которыми можно столкнуться при работе с текстом, отличным от ASCII. Julia упрощает и повышает эффективность работы с обычным текстом ASCII, а работа с Unicode максимально проста и эффективна. В частности, вы можете написать код строк в стиле C для обработки строк ASCII, и он будет работать как ожидается, как по производительности, так и по семантике. Если такой код столкнётся с текстом, отличным от ASCII, он вежливо откажется, выдав чёткое сообщение об ошибке, вместо того, чтобы молча вносить искажённые результаты. В таких случаях изменение кода для обработки данных, отличных от ASCII, является простым.

Вот несколько примечательных высокоуровневых функций строк Julia:

  • Встроенный конкретный тип, используемый для строк (и строковых литералов) в Julia, — это String. Он поддерживает весь диапазон символов Unicode через кодировку UTF-8. (Предоставлена функция transcode() для преобразования в/из других кодировок Unicode.)
  • Все типы строк являются подтипами абстрактного типа AbstractString, а внешние пакеты определяют дополнительные AbstractString подтипы (например, для других кодировок). Если вы определяете функцию, ожидающую строковый аргумент, вы должны объявить тип как AbstractString для того, чтобы принять любой тип строки.
  • Как в C и Java, но в отличие от большинства динамических языков, Julia имеет первый класс, представляющий отдельный символ, называемый Char. Это просто особый вид 32-битного типа данных, численное значение которого представляет собой код Unicode.
  • Как и в Java, строки неизменяемы: значение объекта AbstractString изменить нельзя. Чтобы создать другое строковое значение, необходимо создать новую строку из частей других строк.
  • Понятийно, строка — это частичная функция от индексов к символам: для некоторых значений индексов не возвращается значение символа, а вместо этого выбрасывается исключение. Это позволяет эффективно индексировать строки по индексу байта закодированного представления, а не по индексу символа, который не может быть реализован как эффективно, так и просто для кодировок переменной длины строк Unicode.

Символы

Значение Char представляет собой отдельный символ: это просто 32-битный тип данных со специальным представлением литерала и соответствующим поведением арифметических операций, численное значение которого интерпретируется как код Unicode.

Вот как вводятся и отображаются значения Char.

julia> 'x'
'x'

julia> typeof(ans)
Char

Вы можете легко преобразовать Char в его целочисленное значение, т. е. код символа:

julia> Int('x')
120

julia> typeof(ans)
Int64

На 32-битных архитектурах, typeof(ans) будет Int32. Вы можете преобразовать целочисленное значение обратно в Char с такой же лёгкостью:

julia> Char(120)
'x'

Не все целочисленные значения являются допустимыми кодами Unicode, но для повышения производительности преобразование Char() не проверяет, является ли каждое значение символа допустимым. Если вы хотите проверить, является ли каждое преобразованное значение допустимым кодом символа, используйте функцию isvalid():

julia> Char(0x110000)
'\U110000'

julia> isvalid(Char, 0x110000)
false

На момент написания этой документации допустимые коды Unicode находятся в диапазонах от U+00 до U+d7ff и от U+e000 до U+10ffff. Всем этим значениям ещё не присвоены осмысленные значения, и они не обязательно интерпретируются приложениями, но все эти значения считаются допустимыми символами Unicode.

Вы можете ввести любой символ Unicode в одинарных кавычках, используя \u за которым следуют до четырёх шестнадцатеричных цифр или \U за которым следуют до восьми шестнадцатеричных цифр (самое длинное допустимое значение требует только шести):

julia> '\u0'
'\0'

julia> '\u78'
'x'

julia> '\u2200'
'∀'

julia> '\U10ffff'
'\U10ffff'

Julia использует локаль и языковые настройки вашей системы для определения, какие символы можно выводить как есть, а какие необходимо выводить с помощью универсальных, экранированных \u или \U форм ввода. В дополнение к этим формам ввода эскейпов Unicode можно также использовать все традиционные формы ввода эскейпов C:

julia> Int('\0')
0

julia> Int('\t')
9

julia> Int('\n')
10

julia> Int('\e')
27

julia> Int('\x7f')
127

julia> Int('\177')
127

julia> Int('\xff')
255

Вы можете выполнять сравнения и ограниченное количество арифметических операций со значениями Char:

julia> 'A' < 'a'
true

julia> 'A' <= 'a' <= 'Z'
false

julia> 'A' <= 'X' <= 'Z'
true

julia> 'x' - 'a'
23

julia> 'A' + 1
'B'

Основы строк

Строковые литералы ограничены двойными кавычками или тройными двойными кавычками:

julia> str = "Hello, world.\n"
"Hello, world.\n"

julia> """Contains "quote" characters"""
"Contains \"quote\" characters"

Если вы хотите извлечь символ из строки, вы индексируете её:

julia> str[1]
'H'

julia> str[6]
','

julia> str[end]
'\n'

Весь индексирование в Julia является 1-основанным: первый элемент любого объекта с целочисленным индексом находится под индексом 1, а последний — под индексом n, когда длина строки составляет n.

В любом выражении индексирования ключевое слово end может использоваться в качестве сокращения для последнего индекса (вычисляемого функцией endof(str)). Вы можете выполнять арифметические и другие операции со значениями end, как с обычным значением:

julia> str[end-1]
'.'

julia> str[end÷2]
' '

Использование индекса меньше 1 или больше end приводит к ошибке:

julia> str[0]
ERROR: BoundsError: attempt to access 14-element Array{UInt8,1} at index [0]

julia> str[end+1]
ERROR: BoundsError: attempt to access 14-element Array{UInt8,1} at index [15]

Вы также можете извлечь подстроку с помощью индексирования диапазонов:

julia> str[4:9]
"lo, wo"

Обратите внимание, что выражения str[k] и str[k:k] не дают одинакового результата:

julia> str[6]
','

julia> str[6:6]
","

Первое — это значение одного символа типа Char, а второе — строковое значение, которое случайно содержит только один символ. В Julia это очень разные вещи.

Unicode и UTF-8

Julia полностью поддерживает символы и строки Unicode. Как обсуждалось выше, в литералах символов коды Unicode могут быть представлены с использованием последовательностей эскейпов Unicode \u и \U, а также всех стандартных последовательностей эскейпов C. Эти последовательности также могут использоваться для записи строковых литералов:

julia> s = "\u2200 x \u2203 y"
"∀ x ∃ y"

Отображаются ли эти символы Unicode как эскейпы или как специальные символы, зависит от настроек локали вашего терминала и его поддержки Unicode. Строковые литералы закодированы с помощью кодировки UTF-8. UTF-8 — это кодировка переменной длины, означающая, что не все символы кодируются одинаковым количеством байтов. В UTF-8 символы ASCII — т. е. символы с кодами меньше 0x80 (128) — кодируются так же, как и в ASCII, с использованием одного байта, а коды 0x80 и выше кодируются с использованием нескольких байтов — до четырёх на символ. Это означает, что не каждый индекс байта в строке UTF-8 обязательно является допустимым индексом символа. Если вы индексируете строку по такому недопустимому индексу байта, будет выброшено исключение:

julia> s[1]
'∀'

julia> s[2]
ERROR: UnicodeError: invalid character index
 in slow_utf8_next(::Array{UInt8,1}, ::UInt8, ::Int64) at ./strings/string.jl:67
 in next at ./strings/string.jl:92 [inlined]
 in getindex(::String, ::Int64) at ./strings/basic.jl:70
 ...

julia> s[3]
ERROR: UnicodeError: invalid character index
 in slow_utf8_next(::Array{UInt8,1}, ::UInt8, ::Int64) at ./strings/string.jl:67
 in next at ./strings/string.jl:92 [inlined]
 in getindex(::String, ::Int64) at ./strings/basic.jl:70
 ...

julia> s[4]
' '

В данном случае символ ∀ — это символ с тремя байтами, поэтому индексы 2 и 3 недопустимы, а индекс следующего символа — 4; этот следующий допустимый индекс может быть вычислен с помощью nextind(s,1), а индекс после него — с помощью nextind(s,4) и так далее.

Из-за кодировок переменной длины количество символов в строке (заданное функцией length(s)) не всегда совпадает с последним индексом. Если вы будете перебирать индексы от 1 до endof(s) и индексировать строку s, последовательность возвращаемых символов, когда не происходит ошибки, будет последовательностью символов, составляющих строку s. Таким образом, у нас есть тождество length(s) <= endof(s), так как каждый символ в строке должен иметь свой собственный индекс. Следующее — неэффективный и многословный способ перебора символов в строке s:

julia> for i = 1:endof(s)
           try
               println(s[i])
           catch
               # ignore the index error
           end
       end
∀

x

∃

y

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

julia> for c in s
           println(c)
       end
∀

x

∃

y

Julia по умолчанию использует кодировку UTF-8, и поддержка новых кодировок может быть добавлена пакетами. Например, пакет LegacyStrings.jl реализует типы UTF16String и UTF32String. Более подробное обсуждение других кодировок и способов реализации их поддержки в настоящий момент выходит за рамки этой документации. Более подробная информация о вопросах кодирования UTF-8 представлена в разделе ниже о литералах массивов байтов. Функция transcode() предназначена для преобразования данных между различными кодировками UTF-xx, в основном для работы с внешними данными и библиотеками.

Интерполяция

Одной из самых распространённых и полезных операций со строками является конкатенация:

julia> greet = "Hello"
"Hello"

julia> whom = "world"
"world"

julia> string(greet, ", ", whom, ".\n")
"Hello, world.\n"

Однако создание строк таким образом может стать немного громоздким. Для уменьшения необходимости в этих многословных вызовах string(), Julia позволяет интерполяцию в строковые литералы, используя $, как в Perl:

julia> "$greet, $whom.\n"
"Hello, world.\n"
END_OF_DOCUMENT_MARKER

Это более удобочитаемо и удобно, и эквивалентно приведенному выше конкатенации строк — система переписывает этот, казалось бы, единственный строковый литерал в конкатенацию строковых литералов с переменными.

Самое короткое полное выражение после $ рассматривается как выражение, значение которого должно быть интерполировано в строку. Таким образом, вы можете интерполировать любое выражение в строку, используя скобки:

julia> "1 + 2 = $(1 + 2)"
"1 + 2 = 3"

Как конкатенация, так и интерполяция строк вызывают string() для преобразования объектов в строковую форму. Большинство объектов, не являющихся AbstractString объектами, преобразуются в строки, тесно соответствующие тому, как они вводятся в качестве литеральных выражений:

julia> v = [1,2,3]
3-element Array{Int64,1}:
 1
 2
 3

julia> "v: $v"
"v: [1,2,3]"

string() является тождеством для AbstractString и Char значений, поэтому они интерполируются в строки как таковые, без кавычек и экранирования:

julia> c = 'x'
'x'

julia> "hi, $c"
"hi, x"

Чтобы включить литерал $ в строковый литерал, экранируйте его обратной косой чертой:

julia> print("I have \$100 in my account.\n")
I have $100 in my account.

Строковые литералы в тройных кавычках

Когда строки создаются с использованием тройных кавычек ("""...""") у них есть некоторые особые свойства, которые могут быть полезны для создания более длинных блоков текста. Во-первых, если открывающая """ следует за новой строкой, новая строка удаляется из результирующей строки.

"""hello"""

эквивалентно

"""
hello"""

но

"""

hello"""

будет содержать буквальную новую строку в начале. Конечные пробелы остаются без изменений. Они могут содержать " символы без экранирования. Строки в тройных кавычках также отступляются до уровня наименее отступающей строки. Это полезно для определения строк внутри отступаемого кода. Например:

julia> str = """
           Hello,
           world.
         """
"  Hello,\n  world.\n"

В этом случае последняя (пустая) строка перед закрывающей """ устанавливает уровень отступа.

Обратите внимание, что переводы строк в строковых литералах, будь то одинарные или тройные кавычки, приводят к символу новой строки (LF) \n в строке, даже если ваш редактор использует комбинацию возврата каретки \r (CR) или CRLF для завершения строк. Чтобы включить CR в строку, используйте явное экранирование \r; например, вы можете ввести строку-литерал "a CRLF line ending\r\n".

Общие операции

Вы можете лексикографически сравнивать строки, используя стандартные операторы сравнения:

julia> "abracadabra" < "xylophone"
true

julia> "abracadabra" == "xylophone"
false

julia> "Hello, world." != "Goodbye, world."
true

julia> "1 + 2 = 3" == "1 + 2 = $(1 + 2)"
true

Вы можете искать индекс определенного символа, используя функцию search():

julia> search("xylophone", 'x')
1

julia> search("xylophone", 'p')
5

julia> search("xylophone", 'z')
0

Вы можете начать поиск символа с заданного смещения, предоставив третий аргумент:

julia> search("xylophone", 'o')
4

julia> search("xylophone", 'o', 5)
7

julia> search("xylophone", 'o', 8)
0

Вы можете использовать функцию contains(), чтобы проверить, содержится ли подстрока в строке:

julia> contains("Hello, world.", "world")
true

julia> contains("Xylophon", "o")
true

julia> contains("Xylophon", "a")
false

julia> contains("Xylophon", 'o')
ERROR: MethodError: no method matching contains(::String, ::Char)
Closest candidates are:
  contains(!Matched::Function, ::Any, !Matched::Any) at reduce.jl:489
  contains(::AbstractString, !Matched::AbstractString) at strings/search.jl:310
 ...

Последняя ошибка возникает потому, что 'o' — это литеральный символ, а contains() — это общая функция, которая ищет подпоследовательности. Чтобы искать элемент в последовательности, необходимо использовать in() вместо этого.

Еще две полезные функции для строк — это repeat() и join():

julia> repeat(".:Z:.", 10)
".:Z:..:Z:..:Z:..:Z:..:Z:..:Z:..:Z:..:Z:..:Z:..:Z:."

julia> join(["apples", "bananas", "pineapples"], ", ", " and ")
"apples, bananas and pineapples"

Некоторые другие полезные функции включают:

  • endof(str) возвращает максимальный (байтовый) индекс, который может использоваться для индексирования в str.
  • length(str) — количество символов в str.
  • i = start(str) возвращает первый допустимый индекс, в котором можно найти символ в str (обычно 1).
  • c, j = next(str,i) возвращает следующий символ в или после индекса i и следующий допустимый индекс символа после него. С start() и endof() можно использовать для итерации по символам в str.
  • ind2chr(str,i) возвращает количество символов в str до и включая любой в индексе i.
  • chr2ind(str,j) возвращает индекс, в котором j-й символ в str встречается.

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

В некоторых ситуациях вам нужно создать строку или использовать семантику строк, но поведение стандартного строкового конструктора не совсем то, что нужно. Для таких ситуаций Julia предоставляет нестандартные строковые литералы. Нестандартный строковый литерал выглядит как обычный строковый литерал в двойных кавычках, но непосредственно предваряется идентификатором и ведет себя не совсем как обычный строковый литерал. Соглашение таково, что нестандартные литералы с префиксами в верхнем регистре производят фактические строковые объекты, а те с префиксами в нижнем регистре производят нестроковые объекты, такие как массивы байтов или скомпилированные регулярные выражения. Регулярные выражения, литералы массивов байтов и литералы номеров версий, как описано ниже, являются некоторыми примерами нестандартных строковых литералов. Другие примеры приведены в разделе метапрограммирование.

Регулярные выражения

Julia имеет совместимые с Perl регулярные выражения (regex), как предоставляет библиотека PCRE. Регулярные выражения связаны со строками двумя способами: очевидная связь заключается в том, что регулярные выражения используются для поиска регулярных шаблонов в строках; другая связь заключается в том, что регулярные выражения сами вводятся как строки, которые анализируются в автомат состояния, который можно использовать для эффективного поиска шаблонов в строках. В Julia регулярные выражения вводятся с использованием нестандартных строковых литералов с префиксами различных идентификаторов, начинающихся с r. Самый базовый литерал регулярного выражения без включенных опций просто использует r"...":

julia> r"^\s*(?:#|$)"
r"^\s*(?:#|$)"

julia> typeof(ans)
Regex

Чтобы проверить, соответствует ли regex строке, используйте ismatch():

julia> ismatch(r"^\s*(?:#|$)", "not a comment")
false

julia> ismatch(r"^\s*(?:#|$)", "# a comment")
true

Как можно видеть здесь, ismatch() просто возвращает true или false, указывая, соответствует ли данное регулярное выражение строке или нет. Однако обычно требуется не только узнать, соответствует ли строка, но и как она соответствует. Чтобы захватить эту информацию о соответствии, используйте функцию match() вместо этого:

julia> match(r"^\s*(?:#|$)", "not a comment")

julia> match(r"^\s*(?:#|$)", "# a comment")
RegexMatch("#")

Если регулярное выражение не соответствует данной строке, match() возвращает nothing — специальное значение, которое ничего не печатает в интерактивном запросе. Помимо отсутствия вывода, это совершенно обычное значение, и вы можете программно проверить его:

m = match(r"^\s*(?:#|$)", line)
if m === nothing
    println("not a comment")
else
    println("blank or comment")
end

Если регулярное выражение соответствует, значение, возвращаемое match(), является объектом RegexMatch. Эти объекты записывают, как выражение соответствует, включая подстроку, к которой соответствует шаблон, и любые захваченные подстроки, если они есть. Этот пример захватывает только часть подстроки, которая соответствует, но, возможно, мы хотим захватить любой непустой текст после символа комментария. Мы могли бы сделать следующее:

julia> m = match(r"^\s*(?:#\s*(.*?)\s*$|$)", "# a comment ")
RegexMatch("# a comment ", 1="a comment")

При вызове match() у вас есть возможность указать индекс, с которого начать поиск. Например:

julia> m = match(r"[0-9]","aaaa1aaaa2aaaa3",1)
RegexMatch("1")

julia> m = match(r"[0-9]","aaaa1aaaa2aaaa3",6)
RegexMatch("2")

julia> m = match(r"[0-9]","aaaa1aaaa2aaaa3",11)
RegexMatch("3")

Вы можете извлечь следующую информацию из объекта RegexMatch:

  • вся подстрока, к которой соответствует: m.match
  • захваченные подстроки в виде массива строк: m.captures
  • смещение, с которого начинается полное соответствие: m.offset
  • смещения захваченных подстрок как вектор: m.offsets

Если захват не соответствует, вместо подстроки m.captures содержит nothing в этой позиции, и m.offsets имеет нулевое смещение (вспомните, что индексы в Julia основаны на 1, поэтому нулевое смещение в строке недопустимо). Вот пара несколько искусственных примеров:

julia> m = match(r"(a|b)(c)?(d)", "acd")
RegexMatch("acd", 1="a", 2="c", 3="d")

julia> m.match
"acd"

julia> m.captures
3-element Array{Union{SubString{String},Void},1}:
 "a"
 "c"
 "d"

julia> m.offset
1

julia> m.offsets
3-element Array{Int64,1}:
 1
 2
 3

julia> m = match(r"(a|b)(c)?(d)", "ad")
RegexMatch("ad", 1="a", 2=nothing, 3="d")

julia> m.match
"ad"

julia> m.captures
3-element Array{Union{SubString{String},Void},1}:
 "a"
 nothing
 "d"

julia> m.offset
1

julia> m.offsets
3-element Array{Int64,1}:
 1
 0
 2

Удобно иметь захваты, возвращаемые как массив, чтобы можно было использовать синтаксис деструктуризации для привязки их к локальным переменным:

julia> first, second, third = m.captures; first
"a"

К захватам также можно получить доступ, индексируя объект RegexMatch с номером или именем группы захвата:

julia> m=match(r"(?<hour>\d+):(?<minute>\d+)","12:45")
RegexMatch("12:45", hour="12", minute="45")
julia> m[:minute]
"45"
julia> m[2]
"45"

К захватам можно обратиться в строке подстановки при использовании replace(), используя \n для ссылки на n-ю группу захвата и предваряя строку подстановки s. Группа захвата 0 ссылается на весь объект соответствия. Имена групп захвата можно указать в подстановке с помощью g<groupname>. Например:

julia> replace("first second", r"(\w+) (?<agroup>\w+)", s"\g<agroup> \1")
"second first"

Номерные группы захвата также можно указать как \g<n> для ясности, как в:

julia> replace("a", r".", s"\g<0>1")
"a1"

Вы можете изменить поведение регулярных выражений, используя комбинацию флагов i, m, s, и x после закрывающей двойной кавычки. Эти флаги имеют то же значение, что и в Perl, как объяснено в этом отрывке из справки perlre manpage:

i   Do case-insensitive pattern matching.

    If locale matching rules are in effect, the case map is taken
    from the current locale for code points less than 255, and
    from Unicode rules for larger code points. However, matches
    that would cross the Unicode rules/non-Unicode rules boundary
    (ords 255/256) will not succeed.

m   Treat string as multiple lines.  That is, change "^" and "$"
    from matching the start or end of the string to matching the
    start or end of any line anywhere within the string.

s   Treat string as single line.  That is, change "." to match any
    character whatsoever, even a newline, which normally it would
    not match.

    Used together, as r""ms, they let the "." match any character
    whatsoever, while still allowing "^" and "$" to match,
    respectively, just after and just before newlines within the
    string.

x   Tells the regular expression parser to ignore most whitespace
    that is neither backslashed nor within a character class. You
    can use this to break up your regular expression into
    (slightly) more readable parts. The '#' character is also
    treated as a metacharacter introducing a comment, just as in
    ordinary code.

Например, следующее регулярное выражение включает все три флага:

julia> r"a+.*b+.*?d$"ism
r"a+.*b+.*?d$"ims

julia> match(r"a+.*b+.*?d$"ism, "Goodbye,\nOh, angry,\nBad world\n")
RegexMatch("angry,\nBad world")

Также поддерживаются строковые литералы регулярных выражений с тройными кавычками, вида r"""...""", (они могут быть удобны для регулярных выражений, содержащих кавычки или новые строки).

Массивы байтов

Другим полезным нестандартным строковым литералом является литерал массива байтов: b"...". Эта форма позволяет использовать запись строк для представления литеральных массивов байтов — т.е. массивов UInt8 значений. Правила для литералов массивов байтов следующие:

  • Символы ASCII и ASCII-экранирование дают один байт.
  • \x и восьмеричные escape-последовательности дают байт, соответствующий значению escape.
  • Unicode-escape-последовательности дают последовательность байтов, кодирующую этот код символа в UTF-8.

Существует некоторое перекрытие между этими правилами, так как поведение \x и восьмеричных escape-последовательностей меньше 0x80 (128) покрываются и первыми двумя правилами, но здесь эти правила согласованы. Вместе эти правила позволяют легко использовать символы ASCII, произвольные значения байтов и последовательности UTF-8 для получения массивов байтов. Вот пример, использующий все три:

julia> b"DATA\xff\u2200"
8-element Array{UInt8,1}:
 0x44
 0x41
 0x54
 0x41
 0xff
 0xe2
 0x88
 0x80

ASCII-строка “DATA” соответствует байтам 68, 65, 84, 65. \xff даёт один байт 255. Unicode-escape \u2200 кодируется в UTF-8 как три байта 226, 136, 128. Обратите внимание, что полученный массив байтов не соответствует допустимой UTF-8 строке — если вы попытаетесь использовать его как обычный строковый литерал, вы получите синтаксическую ошибку:

julia> "DATA\xff\u2200"
ERROR: syntax: invalid UTF-8 sequence
 ...

Также обратите внимание на существенное различие между \xff и \uff: первая escape-последовательность кодирует байт 255, в то время как вторая escape-последовательность представляет код символа 255, который кодируется как два байта в UTF-8:

julia> b"\xff"
1-element Array{UInt8,1}:
 0xff

julia> b"\uff"
2-element Array{UInt8,1}:
 0xc3
 0xbf

В литералах символов это различие игнорируется и \xff может представлять код символа 255, потому что символы всегда представляют коды символов. Однако в строках escape-последовательности \x всегда представляют байты, а не коды символов, в то время как \u и \U escape-последовательности всегда представляют коды символов, которые кодируются в один или несколько байтов. Для кодов символов меньше \u80, оказывается, что UTF-8 кодирование каждого кода символа является просто единственным байтом, созданным соответствующей \x escape-последовательностью, поэтому различие можно безопасно игнорировать. Однако для escape-последовательностей \x80 через \xff по сравнению с \u80 через \uff есть существенное различие: первые escape-последовательности кодируют все одиночные байты, которые — если за ними не следуют очень специфические продолжения байтов — не образуют допустимые данные UTF-8, в то время как последние escape-последовательности представляют все коды символов с двухбайтовым кодированием.

Если это все чрезвычайно запутанно, попробуйте прочитать “The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets”. Это отличное введение в Unicode и UTF-8, и может помочь развеять некоторые сомнения по этому вопросу.

Литералы номеров версий

Номера версий легко выражаются с помощью нестандартных строковых литералов вида v"...". Литералы номеров версий создают объекты VersionNumber, которые следуют спецификациям семантического управления версиями и, следовательно, состоят из основных, второстепенных и дополнительных числовых значений, за которыми следуют пре-релизные и билдовые альфа-цифровые аннотации. Например, v"0.2.1-rc1+win64" разбит на главную версию 0, второстепенную версию 2, дополнительную версию 1, пре-релиз rc1 и билда win64. При вводе литерала версии все, кроме номера главной версии, является необязательным, поэтому, например, v"0.2" эквивалентно v"0.2.0" (с пустыми аннотациями пре-релиза/билда), v"2" эквивалентно v"2.0.0", и так далее.

Объекты VersionNumber в основном полезны для легкого и корректного сравнения двух (или более) версий. Например, константа VERSION содержит номер версии Julia в виде объекта VersionNumber, и поэтому можно определить некоторое поведение, специфичное для версии, с помощью простых операторов, таких как:

if v"0.2" <= VERSION < v"0.3-"
    # do something specific to 0.2 release series
end

Обратите внимание, что в приведенном выше примере используется нестандартный номер версии v"0.3-" с последующим -: эта запись является расширением Julia стандартной записи и используется для обозначения версии, которая ниже, чем любая 0.3 версия, включая все ее пре-релизы. Таким образом, в приведенном выше примере код будет выполняться только со стабильными 0.2 версиями и исключит такие версии, как v"0.3.0-rc1". Чтобы также разрешить нестабильные (т.е. предварительные) 0.2 версии, проверка нижней границы должна быть изменена следующим образом: v"0.2-" <= VERSION.

Еще одно расширение нестандартной спецификации версии позволяет использовать конечное + для выражения верхней границы билдов версий, например, VERSION > v"0.2-rc1+" может означать любую версию выше 0.2-rc1 и любой из её билдов: она вернёт false для версии v"0.2-rc1+win64" и true для v"0.2-rc2".

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

Помимо использования для константы VERSION, объекты VersionNumber широко используются в модуле Pkg для указания версий пакетов и их зависимостей.

© 2009–2016 Jeff Bezanson, Stefan Karpinski, Viral B. Shah, and other contributors
Licensed under the MIT License.
https://docs.julialang.org/en/release-0.5/manual/strings/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API