Советы и рекомендации по разделению строк в Джулии
Разбиение строки — одна из самых распространенных операций, которую вы можете выполнять в любом языке программирования. В этой статье мы рассмотрим различные способы разбиения строк в Julia, включая обширные примеры различных подходов.
Правка: мой соавтор и я рады сообщить, что предварительные заказы на нашу новую книгу «Ускоренный курс Джулии» уже доступны:
Основной синтаксис разделения 🖖
Мы начнем с объявления базовой строки:
julia> my_string = "Hello.World" "Hello.World"
Затем мы вызовем функцию split()
и передадим строку, а также разделитель (то, что вы хотите разделить).
julia> split_strings = split(my_string, ".") 2-element Vector{SubString{String}}: "Hello" "World"
В этом случае, поскольку в строке был только 1 период, мы получаем две отдельные строки. Обратите внимание, что в новые строки не включен разделитель, поэтому общая длина объединенных строк в этом случае уменьшилась на 1. Давайте рассмотрим более надежный пример разделения строки:
julia> my_sentence = "Hello world. This is an extended example with more sentences to show what happens. I am going to add only a few more. Okay, last one. Wait, what is this?"
Я просто хочу подчеркнуть, как это выглядит, когда нужно разделить больше элементов. Давайте посмотрим на это в действии:
julia> split_sentences = split(my_sentence, ".") 5-element Vector{SubString{String}}: "Hello world" " This is an extended example with more sentences to show what happens" " I am going to add only a few more" " Okay, last one" " Wait, what is this?"
Обратите внимание, что снова знаки препинания исчезли, но в начале предложения есть пробел. Нам пришлось бы использовать вызов функции strip
, чтобы удалить его.
На данный момент это самая основная форма использования функции split
. Далее мы рассмотрим более продвинутые варианты использования!
Еще одна вещь, о которой следует помнить, это то, что если мы не укажем разделитель, функция split
по умолчанию использует пробел в качестве разделителя, если вы забудете добавить его, вы получите совершенно другой результат:
julia> split_sentences = split(my_sentence) 30-element Vector{SubString{String}}: "Hello" "world." "This" "is" ⋮ "what" "is" "this?"
Расширенные примеры разделения 🧗
Если вы хотите выйти за рамки основ использования split
и попробовать несколько продвинутых примеров, этот раздел для вас. Мы начнем с игры с необязательным аргументом limit
, который позволяет нам установить максимальное количество элементов, которые мы хотим создать.
julia> split_sentences = split(my_sentence, limit=10) 10-element Vector{SubString{String}}: "Hello" "world." ... "with" "more" "sentences to show what happens." ⋯ 40 bytes ⋯ ", last one. Wait, what is this?"
Поскольку мы установили ограничение на 10, мы фактически прекращаем разбиение по разделителю после 10-го элемента. Последний элемент в этом векторе содержит несколько предложений.
Далее мы рассмотрим необязательный аргумент keepempty
. Это позволяет нам указать, хотим ли мы сохранить пустые элементы в результирующем векторе. Вероятно, проще всего увидеть это на практике. Мы переопределим нашу строку, чтобы включить больше текста:
julia> my_sentence = "Hello world. This is an extended example with more sentences to show what happens. I am going to add only a few more. Okay, last one. Wait, what is this? . . . . . . . . ........" "Hello world. This is an extended example with more sentences to show what happens. I am going to add only a few more. Okay, last one. Wait, what is this? . . . . . . . . ........"
Теперь давайте посмотрим на это в действии с обоими вариантами:
julia> split_sentences = split(my_sentence, ".", keepempty=false) 13-element Vector{SubString{String}}: "Hello world" " This is an extended example with more sentences to show what happens" " I am going to add only a few more" " Okay, last one" " Wait, what is this? " ... " " " "
Здесь мы видим, что, поскольку keep empty имеет значение false, у нас нет результирующих элементов, где значением является пустая строка (""
). Если мы изменим значение на true, мы получим следующее:
julia> split_sentences = split(my_sentence, ".", keepempty=true) 21-element Vector{SubString{String}}: "Hello world" " This is an extended example with more sentences to show what happens" " I am going to add only a few more" " Okay, last one" " Wait, what is this? " " " ⋮ "" ""
Опять же, поскольку в исходном примере много точек подряд ( .......
), параметр keepempty
, установленный на true
, дал нам кучу пустых строк.
Это все, что мы можем сделать с базовой функцией split
. Давайте рассмотрим некоторые другие способы обработки разбиения строк в Julia!
Base.rsplit
( )— Начиная с конца 🧵
Подобно функции разделения, существует также функция rsplit
, которая делает то же самое, что и функция разделения, но начинается с конца (хотя, что интересно, порядок результирующих данных не меняется на обратный). Рассмотрим простой пример на практике:
julia> my_string = "Hello.World.This.Is.A.Test" "Hello.World.This.Is.A.Test"
Теперь давайте сравним, чем это отличается от обычной функции split
:
julia> a = split(my_string, ".") 6-element Vector{SubString{String}}: "Hello" "World" "This" "Is" "A" "Test" julia> b = rsplit(my_string, ".") 6-element Vector{SubString{String}}: "Hello" "World" "This" "Is" "A" "Test" julia> a == b true
Но подождите секунду, если rsplit
это:
Аналогично
split
, но начиная с конца строки.
почему не инвертирует порядок? Что ж, это отличный вопрос и то, что я задал на Stack Overflow, чтобы попытаться получить контекст для этого.
Самый большой раз это будет иметь значение, если вы предоставите аргумент limit. В этом случае результаты будут другими:
julia> a = split(my_string, "."; limit=2) 2-element Vector{SubString{String}}: "Hello" "World.This.Is.A.Test" julia> b = rsplit(my_string, "."; limit=2) 2-element Vector{SubString{String}}: "Hello.World.This.Is.A" "Test" julia> a == b false
Все остальные параметры аргумента остаются верными для rsplit
, поэтому нет необходимости повторно хэшировать эти детали.
Использование eachsplit
— введено в Юлии 1️⃣.8️⃣
В Julia 1.8+ есть новая функция eachsplit
, которая позволяет вам разделять элементы так же, как мы это делали раньше, но в этом случае мы по умолчанию возвращаем итератор. Это может быть полезно, когда вы хотите работать с итератором, а не просто возвращать вектор по умолчанию. Давайте посмотрим на это в действии:
julia> a = "Ma.rch" "Ma.rch" julia> split(a, ".") 2-element Vector{SubString{String}}: "Ma" "rch" julia> eachsplit(a, ".") Base.SplitIterator{String, String}("Ma.rch", ".", 0, true)
Теперь, если мы хотим воспроизвести поведение функции split
, нам нужно сделать следующее:
julia> collect(eachsplit(a, ".")) 2-element Vector{SubString}: "Ma" "rch"
Функция collect
позволяет нам объединять элементы через итератор. Лично я думаю, что документация здесь нуждается в некотором улучшении, поэтому у меня есть открытая проблема, направленная на решение этой проблемы.
Но что такое итератор для начала? Ну, согласно документам:
Последовательная итерация реализуется функцией iterate. Вместо того, чтобы изменять объекты по мере их повторения, итераторы Julia могут отслеживать состояние итерации вне объекта. Возвращаемое значение от iterate всегда либо кортеж значения и состояния, либо ничего, если не осталось элементов.
Если вы хотите узнать об этом больше, ознакомьтесь с разделом полная документация по итераторам.
Подводим итоги 🎁
В этом посте мы рассмотрели основы использования функции split
вместе с rsplit
и eachsplit
. Эти функции обеспечивают базовую основу для разделения строк в Julia.
В String-averse (ха, понял) есть еще много всего, что можно исследовать. Я предлагаю проверить https://github.com/JuliaString/Strs.jl в качестве отправной точки для того, что возможно!