Concatenate Binaries and Strings in Erlang
Concatenating strings and binaries in Erlang can get ugly quick. Let's make it easier.
The Problem
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.
lists:concat(["one",5,asdf,1.25]).
% "one5asdf1.25000000000000000000e+00"
The Solution
Here's a small snippet with some eunit tests 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 find a better way to do this, let me know!
Spread the Word