2

假设我想要一个函数,它接受一个数字并将其作为字符串返回,与给出的完全一样。以下不起作用:

SetAttributes[foo, HoldAllComplete];
foo[x_] := ToString[Unevaluated@x]

foo[.2]和的输出foo[.20]是相同的。

我想这样做的原因是我想要一个可以理解以点为分隔符的日期的函数,例如f[2009.10.20]. 我意识到这是对 Mathematica 的一种奇怪的滥用,但我正在制作一种特定于领域的语言,并希望通过执行 eval (ToExpression) 来使用 Mathematica 作为它的解析器。如果我可以依赖两位数的日期和月份,我实际上可以完成这项工作,比如 2009.01.02 但我也想允许 2009.1.2 最终归结为上述问题。

我怀疑唯一的答案是将事物作为字符串传递然后解析它,但也许有一些我不知道的技巧。请注意,这与这个问题有关: Mathematica: Unevaluated vs Defer vs Hold vs HoldForm vs HoldAllComplete vs etc etc

4

3 回答 3

6

我不会依赖 Mathematica 的浮点解析。相反,我会在MakeExpressionfor上定义规则foo。这允许您在将输入解析为浮点数之前将其截取为框。这对规则应该是一个很好的起点,至少对于StandardForm

MakeExpression[RowBox[{"foo", "[", dateString_, "]"}], StandardForm] :=
  With[{args = Sequence @@ Riffle[StringSplit[dateString, "."], ","]},
    MakeExpression[RowBox[{"foo", "[", "{", args, "}", "]"}], StandardForm]]

MakeExpression[RowBox[{"foo", "[", RowBox[{yearMonth_, day_}], "]"}], 
    StandardForm] :=
  With[{args = 
    Sequence @@ Riffle[Append[StringSplit[yearMonth, "."], day], ","]},
      MakeExpression[RowBox[{"foo", "[", "{", args, "}", "]"}], StandardForm]]

我需要第二条规则,因为如果您尝试在数字中添加第二个小数位,笔记本界面将“有用地”插入一个空格。

编辑:为了从内核中使用它,您需要使用前端,但这在版本 7 中通常很容易。如果您可以将表达式作为字符串,请UsingFrontEnd结合使用ToExpression

 UsingFrontEnd[ToExpression["foo[2009.09.20]", StandardForm]

编辑2:如果你想玩,有很多可能性$PreRead,它允许你在解析输入之前对输入应用特殊处理,如字符串。

于 2009-10-27T13:20:22.557 回答
3
$PreRead = If[$FrontEnd =!= Null, #1, 
StringReplace[#,x:NumberString /; StringMatchQ[x,"*.*0"] :>
     StringJoin[x, "`", ToString[
       StringLength[StringReplace[x, "-" -> ""]] - 
        Switch[StringTake[StringReplace[x, 
           "-" -> ""], 1], "0", 2, ".", 1, _, 
         1]]]]] & ; 

将 foo[.20] 显示为 foo[0.20]。它的 InputForm 将是 foo[0.2`2.]

我发现在 Mathematica 中解析和显示数字格式比应有的困难......

于 2010-02-16T10:54:06.100 回答
1

浮点数是,IIRC,由 Mathematica 解析成实际的浮点数,所以没有真正的方法可以做你想做的事。

于 2009-10-27T00:57:02.090 回答