splitting of binaries - erlang

I tried to split two fields from a binary string:
-define(S,<<"M\0\0\0522039355099,010100000008,0,010170000000,0,0,0,0,0,0,,,0,0,,‌​0110,00,150,0,0,0\0">>).<<Message_length:4/binary,Msg/binary>> = S.
the first 4 bytes are the length of the following message, the other byte are the message,
a null byte terminates the string.
The result is:
** exception error: o match of right hand side value
EDIT
Just before the given code, there is:
[Sequence|Reste] = binary:split(T,<<"\0">>),
Does "Reste" bounded ?

Your code is ok, so either you dont have a binary string, or the length of Mystring does not comply with the pattern. Here's a quick test:
1> Mystring = <<"abcde">>.
<<"abcde">>
2> <<Message_length:4/binary,Msg/binary>> = Mystring.
<<"abcde">>
3> Message_length.
<<"abcd">>
4> Msg.
<<"e">>
If you have a string (a list of integers) instead of a binary string (<<"string">>), as Vincenzo suggested, call erlang:list_to_binary/1 first.
Hope it helps
EDIT: I've checked the example string you left in a comment of Vincenzo's answer. I've tried it with your code and still works. Is it possible that Message_length and/or Msg are already bound (and different to Mystring) when reaching that line of code? That would make the pattern matching fail.
EDIT2: Tested with the updated data in the question:
1> S = <<"M\0\0\0522039355099,010100000008,0,010170000000,0,0,0,0,0,0,,,0,0,,\342\200\214\342\200\2130110,00,150,0,0,0\0">>.
<<77,0,0,42,50,48,51,57,51,53,53,48,57,57,44,48,49,48,49,
48,48,48,48,48,48,48,56,44,48,...>>
2> <<Message_length:4/binary,Msg/binary>> = S.
<<77,0,0,42,50,48,51,57,51,53,53,48,57,57,44,48,49,48,49,
48,48,48,48,48,48,48,56,44,48,...>>
3> Message_length.
<<77,0,0,42>>
4> Msg.
<<"2039355099,010100000008,0,010170000000,0,0,0,0,0,0,,,0,0,,\342"...>>

There is issue with erlang string escape interpolation. The fourth byte is not interpolated as "\0" but "\052".
1> Bin = <<"M\0\0\0522039355099,010100000008,0,010170000000,0,0,0,0,0,0,,,0,0,,0110,00,150,0,0,0\0">>.
<<77,0,0,42,50,48,51,57,51,53,53,48,57,57,44,48,49,48,49,
48,48,48,48,48,48,48,56,44,48,...>>
So you have to write it in this manner.
2> f().
ok
3> Bin = <<"M\0\0\0","522039355099,010100000008,0,010170000000,0,0,0,0,0,0,,,0,0,,0110,00,150,0,0,0\0">>.
<<77,0,0,0,53,50,50,48,51,57,51,53,53,48,57,57,44,48,49,
48,49,48,48,48,48,48,48,48,56,...>>
Then usual way to parse this form of messages is:
4> <<L:32/little,Rest/binary>> = Bin.
<<77,0,0,0,53,50,50,48,51,57,51,53,53,48,57,57,44,48,49,
48,49,48,48,48,48,48,48,48,56,...>>
5> L.
77
6> <<Msg:L/binary,R/binary>> = Rest.
<<"522039355099,010100000008,0,010170000000,0,0,0,0,0,0,,,0,0,,0110,00,150,0,0,0"...>>
7> R.
<<0>>
8> Msg.
<<"522039355099,010100000008,0,010170000000,0,0,0,0,0,0,,,0,0,,0110,00,150,0,0,0">>

You have to call list_to_binary/1 on string to be matched.
If you have further problems, type example string please!

Related

How to return a formatted string in Erlang?

Assume you're coding in golang, you can do something like:
str := fmt.Sprintf("%d is bigger than %d", 6, 4)
How about Erlang?
The Erlang equivalent would be
Str = io_lib:format("~p is bigger than ~p", [6, 4])
Note that, even if the result may be not technically a string, normally there is no need to convert it to the string by calling lists:flatten. The result of the format function usually is a special case of iolist. Virtually all Erlang functions expecting a string accept iolists as arguments as well.
"Usually" above means "if Unicode modifier is not used in the format string". In most cases there is no need to use Unicode modifiers, and the result of format can be used directly as described above.
There is io_lib:format/2, that does the job, but note that it returns a possibly nested list of chars, not a string. For a proper string, you have to flatten/1 it afterwards:
lists:flatten(io_lib:format("~p is bigger than ~p", [6, 4]))
To use io_lib:format/2 with unicode characters:
50> X = io_lib:format("~s is greater than ~s", [[8364], [36]]).
** exception error: bad argument
in function io_lib:format/2
called as io_lib:format("~s is greater than ~s",[[8364],"$"])
51> X = io_lib:format("~ts is greater than ~s", [[8364], [36]]).
[[8364],
32,105,115,32,103,114,101,97,116,101,114,32,116,104,97,110,
32,"$"]
52> io:format("~s~n", [X]).
** exception error: bad argument
in function io:format/2
called as io:format("~s~n",
[[[8364],
32,105,115,32,103,114,101,97,116,101,114,32,116,
104,97,110,32,"$"]])
*** argument 1: failed to format string
53> io:format("~ts~n", [X]).
€ is greater than $
ok

How to print an empty string in Erlang

I want to print an empty string like this one "", but erlang gives an empty list [].
I tried with some options ~s, ~w from the io, io_lib modules and it doesnt work.
io_lib:format("~s",[""]).
-> [[]]
io_lib:format("~s",['']).
-> []
io:format("~p",[""]).
-> []
Can anyone show me the proper way to get "" as output?
It mostly depends on what you understand as printing an empty string.
In Erlang, an empty string is equivalent to an empty list. So, if you try to just print it, you'll get that:
1> AnEmptyString = "".
[]
2> io:format("~p~n", [AnEmptyString]).
[]
ok
If you want to print the string that is empty… well… since it's empty, it has no characters, therefore…
3> io:format(">~s<~n", [AnEmptyString]).
><
ok
So, if you want to just print two consecutive double quotes, you'll have to just do that by hand:
4> io:format("~s~n", ["\"\""]).
""
ok
Just keep in mind that you're not printing an empty string there, you're printing a string with just two double quotes 🤷‍♂️
This is not pretty, but you need to put characters explicitly in case of an empty string. Does this work for you ?
6> io:format("~s~n", [fun([]) -> "\"\"";(S) -> S end("")]).
""
ok
7> io:format("~s~n", [fun([]) -> "\"\"";(S) -> S end("\"non-empty string\"")]).
"non-empty string"
ok
8>
The Erlang don't have a type as string, please see a documentation - http://erlang.org/doc/reference_manual/typespec.html. But if you want output something like "", you can try use character adaptation like "\"\"" in io lib, but if you will try know the type of what you try output you will get the same type as list. Eg:
1> [H|T] = io_lib:format("~p~n", ["\"\""]).
["\"\\\"\\\"\"",10]
is_list(H).
true
2>

Erlang printing hex instead of integer

I have been trying to fix a problem for hours now, very new to erlang
lists:sublist([6,9,15,24,39,6,96],7,1).
I want this to print "100" instead of "d"
what I am i doing wrong here?
The shell is going to try to print strings as strings whenever it would be legal. That means lists of integers that happen to all be valid characters will be printed as characters, and lists that contain other things will be printed as lists:
1> [65,66,67].
"ABC"
2> [3,65,66,67].
[3,65,66,67]
But notice that I did not actually call any output functions. That was just the shell's convenience operation of implicitly echoing whatever a returned value was so you, as a programmer, can inspect it.
If I want to explicitly call an output function I should use a format string that specifies the nature of the values to be interpolated:
3> io:format("This is a list: ~tw~n", [List]).
This is a list: [65,66,67]
ok
4> io:format("This is a list rendered as an implied string: ~tp~n", [List]).
This is a list rendered as an implied string: "ABC"
ok
5> io:format("This is a string: ~ts~n", [List]).
This is a string: ABC
ok
Note the additional atom ok after each print. That is because the return value from io:format/2 is ok. So we are getting the explicit output from format/2 and then seeing its return value.
The io module doc page has the gritty details: http://erlang.org/doc/man/io.html#format-1
Back to your example...
6> lists:sublist([6,9,15,24,39,6,96],7,1).
"`"
7> io:format("~tw~n", [lists:sublist([6,9,15,24,39,6,96],7,1)]).
[96]
ok
Addendum
There is a setting called shell:strings/1 that tells the shell to turn string formatting on and off:
1> [65,66,67].
"ABC"
2> shell:strings(false).
true
3> [65,66,67].
[65,66,67]
4> <<65,66,67>>.
<<65,66,67>>
5> shell:strings(true).
false
6> <<65,66,67>>.
<<"ABC">>
But I don't mess with this setting ever anymore for a few reasons:
It is almost never worth the effort to remember this detail of the shell (convenience output from the shell is mostly useful for discovering return value structures, not specific values held by those structures -- and when you want that data you usually want strings printed as strings anyway).
It can cause surprising shell output in any case where you really are dealing with strings.
This is almost never the behavior you actually want.
When dealing with real programs you will need actual output functions using io or io_lib modules, and developing habits around format strings is much more useful than worrying over convenience output from the shell.

Converting a tuple to a string in erlang language

Tuple={<<"jid">>,Member},
Tuple_in_string=lists:flatten(io_lib:format("~p", [Tuple])),
it gives output as:
"{<<\"jid\">>,\"sdfs\"}"
But i want this output without these slashes like
"{<<"jid">>,Member}"
Any pointers?
I have tried all the answers but at the end with io:format("\"~s\"~n", [Tuple_in_string]). what am geeting is "{<<"jid">>,Member}" but it is not a string.it is a atom.I need string on which i can apply concat operation.Any pointers?
You can print it like this:
io:format("\"~s\"~n", [Tuple_in_string]).
It prints:
"{<<"jid">>,"sdfs"}"
The \ are here to denote that the following " is part of the string and not a string delimiter. they do not exist in the string itself. They appear because you use the pretty print format ~p. If you use the string format ~s they wont appear in the display.
1> io:format("~p~n",["a \"string\""]).
"a \"string\""
ok
2> io:format("~s~n",["a \"string\""]).
a "string"
ok
3> length("a \"string\""). % is 10 and not 12
10
Firstly, you don't need to flatten the list here:
Tuple_in_string=lists:flatten(io_lib:format("~p", [Tuple])),
Erlang has the concept of iodata(), which means that printable things can be in nested lists and most functions can handle them, so you should leave only:
Tuple_in_string = io_lib:format("~p", [Tuple]),
Secondly, when you use ~p, you tell Erlang to print the term in such way, that it can be copied and pasted into console. That is why all double quotes are escaped \". Use ~s, which means "treat as string".
1> 38> Tuple = {<<"jid">>,"asdf"}.
{<<"jid">>,"asdf"}
2> IODATA = io_lib:format("~p", [Tuple]).
[[123,[[60,60,"\"jid\"",62,62],44,"\"asdf\""],125]]
3> io:format("~s~n", [IODATA]).
{<<"jid">>,"asdf"}
ok
L = Packet_in_tuple_form={xmlel,<<"message">>,[{<<"id">>,<<"rkX6Q-8">>},{<<"to">>,<<"multicast.devlab">>}],[{xmlel,<<"body">>,[],[{xmlcdata,"Hello"}]},{xmlel,<<"addresses">>,[{<<"xmlns">>,<<"http://jabber.org/protocol/address">>}],[{xmlel,<<"address">>,[{<<"type">>,<<"to">>},"{<<\"jid\">>,\"sds\"}",{<<"desc">>,"Description"}],[]}]}]}.
Gives me:
{xmlel,<<"message">>,
[{<<"id">>,<<"rkX6Q-8">>},{<<"to">>,<<"multicast.devlab">>}],
[{xmlel,<<"body">>,[],[{xmlcdata,"Hello"}]},
{xmlel,<<"addresses">>,
[{<<"xmlns">>,<<"http://jabber.org/protocol/address">>}],
[{xmlel,<<"address">>,
[{<<"type">>,<<"to">>},
"{<<\"jid\">>,\"sds\"}",
{<<"desc">>,"Description"}],
[]}]}]}
The \ in the address field are escape characters.
You can verify the same by checking the length of string.

Erlang - io:format 's result / (formatting with io_lib:format/2)

I'm trying to get the result of the output of io:format/1.
I know that there's a similar function in io_lib, io_lib:format/2, but the output is different. In fact, it doesn't do anything at all.
If I try to bound io:format, ok is bounded, and the formatted string is written out to the console.
So my question is, how can I get the same output with io_lib:format/2?
Or how can I bound the formatted string to a variable?
1> A = io:get_line('> ').
> "test".
"\"test\".\n"
2> io:format(A).
"test".
ok
3> B = io_lib:format(A, []).
"\"test\".\n"
4> B.
"\"test\".\n"
5> C = io:format(A).
"test".
ok
6> C.
ok
io_lib:format is not an output function the way io:format is. Instead io_lib:format only returns the value, but does not output it.
The result of io:format that you see as "test." is the rendered version as sent to the terminal (including the newline) , then it returns ok. Conversely, the return value of io_lib:format that you see as "\"test\".\n" is simply the erlang shell's representation of the same string, with the quotes and newline escaped, and surrounded by its own quotes.
io_lib:format is more commonly used for inserting values into the strings (similar to C's printf functions). For example, doing something like
NewString = io_lib:format("The string entered was ~s I hope you like it",[A])
The value of NewString would be
The string entered was "test".
I hope you like it
For which the Erlang Shell's representation would be:
"The string entered was \"test\".\n I hope you like it"
If all you want to do is output the value you just entered, then io:format is sufficient for your needs.

Resources