3

如果这个问题命名不当,我深表歉意,但让我通过一个简单的 Java 类比来解释一下。请注意,这个问题是关于 Matlab,而不是 Java。

在 Java 中,写入stdout流的标准方法是说System.out.println. 如果我们想将这个确切的输出打印到文件中,我们可以创建一个PrintStream对象myPrinter,将它指向一个文件,然后将调用替换为System.out.println调用myPrinter.println

System.out.println("Hello World");
PrintStream myPrinter = new PrintStream(new File("MyJournal.log"));
myPrinter.println("Hello Log");

在 Matlab 中,写入标准输出的一种标准方法是编写不带分号的表达式、变量或语句。我将如何重写我的 Matlab 语句以将此(ascii)输出转换为文件?

我想避免重定向stdout到文件的解决方案,因为我仍然希望将某些内容打印到控制台。

此外,我不想指定要写入文件的对象的类型,因为标准方式不需要类型规范。

更新:据我所知,特别printf是函数族需要类型规范(不同的格式字符串取决于对象的类型)。我试图避免这种情况,因为我寻求更通用的解决方案。

4

1 回答 1

7

你想要做的是找到一个看起来像的通用字符串转换display(),使用它来构建你的输出作为字符串,然后你可以将它传递给fprintf()或其他正常的输出函数。

省略分号产生的 Matlab 输出是通过调用display()表达式的结果来完成的。Matlabdisplay为所有内置类型提供了一个实现,并为用户提供的对象提供了一个后备实现。该disp()函数以相同的方式显示值,但省略了变量名。

这基本上相当于 Java 的toString函数,当您将任意对象打印到PrintStream. 显示功能大多不在PrintStream其本身,而是在toString知道如何将对象转换为显示字符串的多态方法中。不同之处在于 JavatoString返回一个字符串数据值,该值易于以编程方式使用并与其他操作组合,因此您可以对其进行操作,将其发送到您想要的位置,但 Matlabdisplay始终disp输出到标准输出,而不是返回一个字符串。

你想要的可能是会给你display- 样式输出作为字符串的东西,然后你可以使用fprintf()或其他字符串输出函数将它输出到你想要的地方。

一种简单的方法是用于evalc()调用display和捕获输出。该evalc函数允许您运行任意 Matlab 代码,并捕获本来会stdout转到char变量的输出。您可以制作通用转换函数并将其应用于您想要的任何值。

function out = tostr(x)
    out = evalc('disp(x)');
end

另一种选择是定义一个新dispstr()函数,编写它以转换 Matlab 内置类型(可能使用该技术),并在您编写的对象中evalc覆盖,并以多态方式调用它。dispstr更多的工作,但它最终可能会变得更干净和更快,因为evalc它很慢而且有时很脆弱。还可以查看mat2str有关替代输出机制的想法。

然后,您可以通过这样的调用一般地输出值,而无需指定类型。请注意,在第二种形式中,占位符都只是%s与对象的类型无关。

function displaySomeArbitraryDataValues(fh, foo, bar, baz)
% fh is a file handle previously opened with fopen()
fprintf(fh, 'foo=%s, bar=%s and baz=%s', tostr(foo), tostr(baz), tostr(qux))
end

Matlab没有自动调用显示转换的格式化输出函数,所以很多情况下必须显式调用转换,所以会比Java罗嗦一些。(除非您想全力以赴编写自己的多态自动转换输出函数或字符串包装器对象。)如果您想使用占位符,强制转换所有参数就很容易了。

function out = sprintf2(format, varargin)
%SPRINTF2 A sprintf equivalent with polymorphic input conversion
% Use '%s' placeholders for everything in format, regardless of arg type
args = varargin;
strs = {}
for i = 1:numel(args)
    strs{i} = tostr(args{i});
end
out = sprintf(format, strs{:});
end

如果你想变得花哨,你可以printf通过自己解析printf格式参数来进行混合转换,定义一个新的占位符,就像在参数上%y调用你的那样tostr(),然后打印该字符串(可能通过将占位符替换为结果,%s并将参数替换为tostr()结果),并将所有正常的占位符printf与未转换的参数一起传递给。不过,这有点难以实现,而且计算成本可能很高。

可以char通过提供将对象值转换为显示字符串的转换使其行为更像 Java ,但这与 Matlab 现有的数字到char转换的工作方式不一致,因此它不是完全通用的,并且您会遇到一些奇怪的边缘情况,所以我不建议这样做。您可以通过定义一个@string包装字符串的新类来实现更安全的形式char,但通过调用 yourtostr()而不是char(). 不过,这可能会对性能造成很大影响,因为 Matlab OOP 对象比使用内置类型和普通函数的操作要慢得多。

背景:基本上,您需要fprintf在 Matlab 中传递显式转换,但不需要使用PrintStreamJava 中的东西的原因是它fprintf继承自 C,它没有运行时类型检测,尤其是 varargs,在语言。Matlab 有,所以fprintf比它需要的更有限。然而,什么fprintf确实为您提供了对数值格式的细粒度控制和简洁的调用形式。这些都是有用的,正如 Java 程序员多年来抱怨 Java 中没有它们并最终添加它们所证明的那样。只是 Matlab 坚持使用 C 支持的 fprintf 转换,他们可以轻松地添加几个新的通用转换,在运行时检查输入的类型并为您提供所需的通用输出支持。

于 2013-04-28T22:23:00.673 回答