An Erlang snippet for easily concatenating binaries and strings

0

Full article

There have been a number of times when using Erlang that I've found myself concatenating a list of binaries and strings. I usually resort to manual conversions one way or the other... and I think you'll agree they're both pretty ugly.

<< <<"One">>/binary, (list_to_binary(" Two "))/binary, <<"Three">>/binary, (list_to_binary(" Four!"))/binary >>.
% <<"One Two Three Four!">>


binary_to_list(<<"One">>) ++ " Two " ++ binary_to_list(<<"Three">>) ++ " Four!".
% "One Two Three Four!"

There's a helpful lists:concat function that quickly converts a list of elements to a single string. Unfortunately, the list of allowed types doesn't include binaries. Womp womp.

lists:concat(["one",5,asdf,1.25]).
% "one5asdf1.25000000000000000000e+00"

Snippet for concatenating binaries and strings

Here's a small snippet with some eunit tests (find the gist here) that'll convert binaries to strings, run them through the lists:concat function, then return the binary or string you asked for.

-module(utils).

-export([concat/2]).

%% EXTERNAL

concat(Words, string) ->
    internal_concat(Words);
concat(Words, binary) ->
    list_to_binary(internal_concat(Words)).

%% INTERNAL

internal_concat(Elements) ->
    NonBinaryElements = [case Element of _ when is_binary(Element) -> binary_to_list(Element); _ -> Element end || Element <- Elements],
    lists:concat(NonBinaryElements).

%% EUNIT TESTS

-include_lib("eunit/include/eunit.hrl").

concat_conversion_test_() ->
    [
        {"list of strings to string", ?_assertEqual("This and that.", utils:concat(["This", " and", " that."], string))},
        {"list of strings to binary", ?_assertEqual(<<"This and that.">>, utils:concat(["This", " and", " that."], binary))},
        {"list of binaries to string", ?_assertEqual("This and that.", utils:concat([<<"This">>, <<" and">>, <<" that.">>], string))},
        {"list of binaries to binary", ?_assertEqual(<<"This and that.">>, utils:concat([<<"This">>, <<" and">>, <<" that.">>], binary))},
        {"mix of values to string", ?_assertEqual("This and that 5asdf hi.", utils:concat([<<"This">>, " and", <<" that ">>, 5, asdf, " hi."], string))},
        {"mix of values to binary", ?_assertEqual(<<"This and that 5asdf hi.">>, utils:concat([<<"This">>, " and", <<" that ">>, 5, asdf, " hi."], binary))}
    ].

Usage

To use it, just pass a list of any element types that lists:concat would normally allow, as well as binaries.

utils:concat([<<"One">>, " two ", three, 5, 1.25], binary).
% <<"One two three51.25000000000000000000e+00">>

utils:concat([<<"One">>, " two ", three, 5, 1.25], string).
% "One two three51.25000000000000000000e+00"

If you have a problem with this, or find a better or more efficient way to do it, please let me know!

Author

Grant Winney

Is there anything more satisfying than sharing knowledge? Of teaching someone and witnessing their "ah ha" moment? I usually write about tech, but no promises. I hope you find something interesting!



Comments