5
$\begingroup$

It's a shame that the Export framework provides no support for custom formatting of real numbers. Is it possible to augment the framework so that a "NumberForm" option can be passed in that specifies what NumberForm arguments should be used to format real numbers?

As an example:

ExportString[3.14159, "Text", "NumberForm"->{3, NumberPoint->","}]

should produce:

"3,14"

$\endgroup$

1 Answer 1

5
$\begingroup$

Both Export and ExportString use the common function System`ConvertersDump`ExportInternal to produce their output. In particular, any options that are fed to Export and ExportString will be present as an option to System`ConvertersDump`ExportInternal. So, we can overload this function to enable customized processing of real numbers. There are at least two mechanisms by which the built-in code processes real numbers: The formats "Table", "CSV" and others use CForm to format real numbers, while the format "Text" uses ToString with InputForm to format real numbers. So, the following function modifies both CForm and Real so that custom formatting occurs:

System`ConvertersDump`ExportInternal[channel_, expr_, format_List, opts___] := With[
    {nf = Lookup[Flatten@{opts}, "NumberForm"]},

    With[{args=Sequence@@nf},
        Internal`InheritedBlock[{CForm, Real},
            Unprotect[{Real,CForm}];
            CForm=OutputForm@linearNumberForm[#,args]&;
            Format[r_Real,InputForm]:=OutputForm@linearNumberForm[r,args];
            System`ConvertersDump`ExportInternal[channel,expr,format,"NumberForm"->{},opts]
        ]
    ] /; !MatchQ[nf, {}]
]

linearNumberForm[e_, args__]:=With[{boxes = ToBoxes[NumberForm[e, args]]},
    Replace[boxes,
        TagBox[InterpretationBox[r_, ___],___]:>stringify[r]
    ]
]

stringify[s_String]:=If[StringMatchQ[s,"\"*\""],StringTake[s,{2,-2}],s]
stringify[RowBox[s_]]:=StringJoin[Replace[s, x_:>stringify[x],{1}]]
stringify[SuperscriptBox[_, e_]]:="10^"<>stringify[e]

Examples:

ExportString[N@Pi, "Text", "NumberForm"->{4, NumberPoint->","}]
ExportString[(N@Pi)^100, "Text", "NumberForm"->{{5,5}, NumberMultiplier->"*", ExponentFunction->(#&)}]

"3,142"

"5.18780*10^49"

I haven't checked this code for a variety of NumberForm options, so please try it out and let me know of any deficiencies.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.