Erlang:如何创建一个返回包含YYMMDD格式日期的字符串的函数?

时间:2015-08-29 02:58:21

标签: functional-programming erlang erlang-shell

我正在努力学习Erlang,我正在研究Erlang在网站上的练习问题。其中之一是:

编写函数time:swedish_date(),它返回一个包含瑞典YYMMDD格式日期的字符串:

time:swedish_date()
"080901"

我的功能:

-module(demo).
-export([swedish_date/0]).

swedish_date() ->
[YYYY,MM,DD] = tuple_to_list(date()),
string:substr((integer_to_list(YYYY, 3,4)++pad_string(integer_to_list(MM))++pad_string(integer_to_list(DD)).

pad_string(String) ->
if 
    length(String) == 1 -> '0' ++ String;
    true -> String
end.

我在编译时遇到以下错误。

demo.erl:6: syntax error before: '.'
demo.erl:2: function swedish_date/0 undefined
demo.erl:9: Warning: function pad_string/1 is unused 
error

我该如何解决这个问题?

3 个答案:

答案 0 :(得分:2)

修复编译错误后,您仍然面临运行时错误。由于您正在尝试学习Erlang,因此查看您的方法并查看是否可以改进它并在此过程中修复这些运行时错误是有益的。

首先让我们看一下swedish_date/0

swedish_date() ->
    [YYYY,MM,DD] = tuple_to_list(date()),

为什么要将列表转换为元组?由于您单独使用列表元素并且从不将列表作为一个整体使用,因此转换没有任何意义。你可以改为模式匹配返回的元组:

    {YYYY,MM,DD} = date(),

接下来,您正在调用不存在的string:substr/1

    string:substr((integer_to_list(YYYY,3,4) ++
        pad_string(integer_to_list(MM)) ++
        pad_string(integer_to_list(DD))).

string:substr/2,3 functions都占据起始位置,3-arity版本也需要一个长度。您也不需要,并且可以完全避免string:substr,而只是返回已组装的字符串:

    integer_to_list(YYYY,3,4) ++
        pad_string(integer_to_list(MM)) ++
        pad_string(integer_to_list(DD)).

哎呀,这仍然不对:没有这样的功能integer_to_list/3,所以只需用integer_to_list/1替换第一个来电:

    integer_to_list(YYYY) ++
        pad_string(integer_to_list(MM)) ++
        pad_string(integer_to_list(DD)).

接下来,让我们看一下pad_string/1

pad_string(String) ->
    if
        length(String) == 1 -> '0' ++ String;
        true -> String
    end.

这里有一个运行时错误,因为'0'是一个原子而你正在尝试将String附加到它上面。错误如下所示:

  

**异常错误:错误的论点
  在operator ++ / 2中   称为'0'++“8”

不要直接修复它,让我们考虑pad_string/1的作用:如果字符串是单个数字,它会添加一个前导0字符。而不是使用if来检查这种情况 - 通常在Erlang代码中不使用if - 使用模式匹配:

pad_string([D]) ->
    [$0,D];
pad_string(S) ->
    S.

第一个子句匹配单个元素列表,并返回一个新的列表,其中元素D前面带有$0,这是字符0的字符常量。第二个子句匹配所有其他参数,只返回传入的内容。

以下是包含所有更改的完整版本:

-module(demo).
-export([swedish_date/0]).

swedish_date() ->
    {YYYY,MM,DD} = date(),
    integer_to_list(YYYY) ++
        pad_string(integer_to_list(MM)) ++
        pad_string(integer_to_list(DD)).

pad_string([D]) ->
    [$0,D];
pad_string(S) ->
    S.

但更简单的方法是使用the io_lib:format/2 function直接格式化所需的字符串:

swedish_date() ->
    io_lib:format("~w~2..0w~2..0w", tuple_to_list(date())).

首先,请注意我们已回复调用tuple_to_list(date())。这是因为io_lib:format/2的第二个参数必须是一个列表。它的第一个参数是一个格式字符串,在我们的例子中说它期望三个参数,将每个参数格式化为Erlang术语,并格式化宽度为2和0填充的第二和第三个参数。

但还有一个步骤要解决,因为如果我们运行io_lib:format/2版本,我们会得到:

1> demo:swedish_date().
["2015",["0",56],"29"]

哇,那是什么?它只是一个深层列表,列表中的每个元素本身就是一个列表。为了获得我们想要的格式,我们可以将该列表展平:

swedish_date() ->
    lists:flatten(io_lib:format("~w~2..0w~2..0w", tuple_to_list(date()))).

执行此版本可为我们提供我们想要的内容:

2> demo:swedish_date().
"20150829"

找到下面代码的最终完整版本。

-module(demo).
-export([swedish_date/0]).

swedish_date() ->
    lists:flatten(io_lib:format("~w~2..0w~2..0w", tuple_to_list(date()))).

更新:@Pascal评论年份应打印为2位而不是4位。我们可以通过将日期列表传递给列表理解来实现这一点:

swedish_date() ->
    DateVals = [D rem 100 || D <- tuple_to_list(date())],
    lists:flatten(io_lib:format("~w~2..0w~2..0w", DateVals)).

这会将rem余数运算符应用于tuple_to_list(date())返回的每个列表元素。这个操作对于月份和日期都是不必要的,但我认为它比提取年份和单独处理更清洁。结果:

3> demo:swedish_date().
"150829"

答案 1 :(得分:0)

这里有一些问题:

  1. 您在第6行末尾缺少一个括号。
  2. 当Erlang仅定义integer_to_list/3时,您正试图致电integer_to_list/1,2
  3. 这将有效:

    -module(demo).
    -export([swedish_date/0]).
    
    swedish_date() ->
    [YYYY,MM,DD] = tuple_to_list(date()),
    string:substr(
        integer_to_list(YYYY) ++ 
        pad_string(integer_to_list(MM)) ++ 
        pad_string(integer_to_list(DD))
        ).
    
    pad_string(String) ->
    if 
        length(String) == 1 -> '0' ++ String;
        true -> String
    end.
    

答案 2 :(得分:0)

除了第6行的括号错误外,你还在第10行有一个错误,你可以使用'0'而不是“0”的形式,所以你定义一个原子而不是一个字符串。

我知道你这样做是出于教育目的,但我鼓励你深入了解erlang库,这是你必须要做的事情。对于像这样的常见问题,它已经存在可以帮助您的功能:

swedish_date() ->
    {YYYY,MM,DD} = date(), % not useful to transform into list
    lists:flatten(io_lib:format("~2.10.0B~2.10.0B~2.10.0B",[YYYY rem 100,MM,DD])).
    % ~X.Y.ZB means: uses format integer in base Y, print X characters, uses Z for padding