【问题标题】:Delphi XE3: Convert WideChar array to Unicode string HOWTO?Delphi XE3:将 Wide Char 数组转换为 Unicode 字符串 HOW TO?
【发布时间】:2015-01-29 08:07:39
【问题描述】:

我在这里对上面给出的问题做了一些研究,并提出了以下代码:

VarStr = array of WideChar;

function ArrayToString(const a: VarStr): UnicodeString;
begin
  if Length(a) > 0 then
    begin
      ShowMessage ('Länge des übergebenen Strings: ' + IntToStr(Length(a)));
      SetString(Result, PWideChar(@a[0]), Length(a) div 2)
    end
  else
    Result := '';
end;

ShowMessage 显示给定数组中正确数量的字符,但函数的结果始终为空字符串。

请问你有什么想法?

【问题讨论】:

  • Length(a) div 2 表示只使用了一半的字符。而不是PWideChar(@a[0]),你完全可以写@a[0]。演员阵容是不必要的。但是,如果数组的长度为 0 并且您使用范围检查,则代码将产生运行时错误。你应该这样做。所以我会把它写成PWideChar(a)
  • a[0] , #0 的内容是什么?
  • @bummi 我认为这并不重要SetString 不寻找空终止符
  • @DavidHeffernan 嗯。使用 a[0]=#0 (或未初始化,也许他不知道基于 0)你将得到一个空字符串,而不是缩短的字符串。
  • @DavidHeffernan 不会争辩,他说的是Showmessage,试试a[0] := #0; a[1] := 'b'; a[2] := 'c'; a[3] := 'd'; Showmessage(ArrayToStringBroken(a));

标签: delphi delphi-xe3


【解决方案1】:

您传递了错误的长度值。你只要求一半的字符。像这样修复你的代码:

function ArrayToString(const a: VarStr): string;
begin
  SetString(Result, PWideChar(a), Length(a));
end;

但是,您还报告说您的函数返回一个空字符串。最可能的原因是您将无效输入传递给函数。考虑这个程序:

{$APPTYPE CONSOLE}

type
  VarStr = array of WideChar;

function ArrayToStringBroken(const a: VarStr): UnicodeString;
begin
  SetString(Result, PWideChar(@a[0]), Length(a) div 2);
end;

function ArrayToStringSetString(const a: VarStr): UnicodeString;
begin
  SetString(Result, PWideChar(a), Length(a));
end;

var
  a: VarStr;

begin
  a := VarStr.Create('a', 'b', 'c', 'd');
  Writeln(ArrayToStringBroken(a));
  Writeln(ArrayToStringSetString(a));
end.

输出是:

抗体 A B C D

因此,除了您问题中的代码问题外,您的问题中的代码似乎也存在问题。

也许当你说:

函数的结果总是一个空字符串。

您实际上是指将返回值传递给ShowMessage 时不显示任何文本。那是完全不同的事情。正如@bummi 在 cmets 中指出的那样,ShowMessage 将在遇到的第一个空终止符处截断其输入。使用适当的调试工具检查变量的内容。

【讨论】:

  • 在 XE7 中,var a: VarStr = ['a', 'b', 'c', 'd']; 看起来好多了!
  • FWIW,相当于旧语法 a := VarStr.Create('a', 'b', 'c', 'd');,同样,相当于您使用 SetLength(...); a[0] := ...; 的代码
  • 很容易忘记它们。我几乎不使用它们,因为它们没有优化任何东西。只是打字少了一点。我更喜欢从一个常量数组初始化我的 dynarrays 并编写一个小例程,根据基本类型,逐个元素复制或移动到 dynarray。
  • @RudyVelthuis 我有一个继承自TArray<T> 的静态泛型类,也称为TArray<T>,并允许我写:arr := TArray<Integer>.Copy([1, 2, 3, 4])
  • 我不知道,但这是个好主意。但这同样表现不佳,因为这些值是在运行时“生成”的。但是如何从 TArray(一个通用的动态数组)继承呢?
【解决方案2】:
Result:= Trim(string(a));

更新:正如同事在 cmets 中亲切指出的那样,这是一个错误答案!它之所以有效,只是因为内部字符串和动态数组的实现非常相似,并且不能保证这样的代码在未来的编译器版本中可以工作。 David 的回答中描述了 DynArray->String 转换的正确方法。我不会删除我的答案以保留 cmets,在我看来它们的价值要大得多..

【讨论】:

  • 如果没有 Trim,它应该也能正常工作。修剪也不应该吃最后一个字符(在我的测试示例中它没有这样做)。你的 VarStr 数组有问题。
  • 我不认为 UnicodeStringstring 是同义词的相关性。您在这里展示的重要一点是,即使stringarray of WideCharnot 同义词,也可以对动态数组进行类型转换以告诉编译器它实际上是一个字符串。这不一定直观。
  • 将动态数组类型转换为 string 是错误的。如果您打算这样做,请将数组类型转换为它真正兼容的内容 - PWideChar,例如:Result := UnicodeString(PWideChar(a));。但是,任何一种类型转换都要求数组以空值结尾。如果不是,您必须改用SetString()(他无论如何都应该使用它)。
  • 雷米所说的,简而言之。空终止、零索引的 Char 数组(按设计)与字符串兼容,但动态数组不兼容。这个答案中的代码似乎有效的事实是因为 Char 的动态数组的内部格式类似于字符串的内部格式,但这是一个永远不应该依赖的实现细节 - 实际上,关于是否cast 应包含在 Trim 调用中和/或参与在此附加显式空终止符提示。
  • array of Char 不是string,在这种类型转换期间不会转换为正确的string。它所做的只是诱使编译器认为数组的内存指针指向string 有效负载,但事实并非如此。如果您跟踪您的示例,您将看到数组指针按原样传递给System._Write0UString(),后者将指针按原样传递给System._LStrFromUStr(),这碰巧起作用,因为动态数组有一个length 字段,其内存偏移量与string 相同,但该转换仅适用于array of Char
猜你喜欢
  • 1970-01-01
  • 2018-09-18
  • 1970-01-01
  • 2019-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-04
  • 2015-03-29
相关资源
最近更新 更多