читать нулевую завершенную строку из байтового вектора в юлии - PullRequest
1 голос
/ 17 апреля 2020

У меня есть вектор типа UInt8 и фиксированной длины 10. Я думаю, что он содержит строку с нулевым символом в конце, но когда я делаю String (v), он показывает строку + все нули остального вектора.

v = zeros(UInt8, 10)
v[1:5] = Vector{UInt8}("hello")
String(v)

вывод "hello \ 0 \ 0 \ 0 \ 0 \ 0".

Либо я упаковываю неправильно, либо читаю неправильно. Есть мысли?

Ответы [ 3 ]

3 голосов
/ 17 апреля 2020

Я использую этот фрагмент:

"""
    nullstring(Vector{UInt8})
Interpret a vector as null terminated string.
"""
nullstring(x::Vector{UInt8}) = String(x[1:findfirst(==(0), x) - 1])

Хотя, держу пари, есть более быстрые способы сделать это.

2 голосов
/ 17 апреля 2020

Вы можете использовать unsafe_string: unsafe_string(pointer(v)), это делает это без копирования, поэтому очень быстро. Но решение @ laborg лучше почти во всех случаях, потому что оно безопасно. Если вы хотите и безопасность, и максимальную производительность, вы должны написать ручную функцию самостоятельно:

function get_string(v::Vector{UInt8})
    # Find first zero
    zeropos = 0
    @inbounds for i in eachindex(v)
        iszero(v[i]) && (zeropos = i; break)
    end
    iszero(zeropos) && error("Not null-terminated")
    GC.@preserve v unsafe_string(pointer(v), zeropos - 1)
end

Но, да, каковы шансы, что ДЕЙСТВИТЕЛЬНО вам нужно, чтобы это было так быстро.

1 голос
/ 18 апреля 2020

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

function nullstring!(x::Vector{UInt8})
    i = findfirst(iszero, x)
    SubString(String(x),1,i-1)
end

Обратите внимание, что после вызова x будет пустым, и возвращаемое значение будет Substring, а не String, но во многих Scenar ios это не имеет значения. Этот код делает половину распределения, чем код @laborg и немного быстрее (около 10-20%). Код Джейкоба все еще непобедим.

...