如何在非Unicode版本的Delphi中构建带有变音符号的WideString?

4
我正在尝试构建一个(测试)WideString,其中包含以下内容:

á(U+00E1 小写拉丁字母A,带有重音符号

但是我使用了它的分解形式:

LATIN SMALL LETTER A (U+0061) COMBINING ACUTE ACCENT (U+0301)

因此,我有以下代码片段:

var
    test: WideString;
begin
   test := #$0061#$0301;
   MessageBoxW(0, PWideChar(test), 'Character with diacratic', MB_ICONINFORMATION or MB_OK);
end;

但实际情况是它似乎不起作用:

enter image description here

这可能是MessageBox的一个漏洞,但我认为更有可能是我的代码有问题。

我尝试了一些其他变化:

test := WideString(#$0061#$0301);


const
    SmallLetterLatinAWithAcuteDecomposed: WideString = #$0061#$0301;
test := SmallLetterLatinAWithAcuteDecomposed


test := #$0061+#$0301;  (Doesn't compile; incompatible types)


test := WideString(#$0061)+WideString(#$0301);  (Doesn't compile; crashes compiler)


test := 'a'+WideString(#$0301);  (Doesn't compile; crashes compiler)


//Arnauld's thought:
test := #$0301#$0061;

额外的话题


你使用的是哪个 Delphi 版本?我记得有些版本对编译环境的区域设置比其他版本更敏感。 - Rob Kennedy
1
在D2007上运行良好(已测试第一个代码片段)。 - Sertac Akyuz
1
@Ian 你很棒,尝试从老旧的D5中挖掘一些生命力。但是如果你在D2中完成这个任务,你将获得额外的加分!! ;-) - David Heffernan
让我们为 Delphi 1 献上一些爱吧。16 位应该对任何人都足够了。 - Warren P
2
@David Heffernan:我们公司在你需要签署保密协议才能获取VCL源代码的时候就开始使用D1了! - Ian Boyd
显示剩余2条评论
3个回答

11

最佳答案:

const
    n: WideString = '';  //n=Nothing

s := n+#$0061+#$0301;

这样做可以解决我以下所有无法正常运行的情况。


唯一可行的方法是将其声明为常量:

AccentAcute: WideString = #$0301;
AccentAcute: WideString = WideChar($0301);
AccentAcute: WideString = WideChar(#$0301);
AccentAcute: WideString = WideString(#$0301);

示例用法:

s := 'Pasta'+AccentAcute;

不起作用的基于常量的语法

  • AccentAcute: WideString = $0301;
    类型不兼容
  • AccentAcute: WideString = #0301;
    会得到 enter image description here
  • AccentAcute: WideString = WideString($0301);
    无效的类型转换
  • AccentAcute: WideString = WideString(#$0301);
    无效的类型转换
  • AccentAcute: WideChar = WideChar(#0301); 会得到 Pastai
  • AccentAcute: WideChar = WideChar($0301); 会得到 Pasta´

其他失败的语法

  • 'Pasta'+WideChar($0301)
    会得到 Pasta´
  • 'Pasta'+#$0301
    会得到 Pasta´
  • WideString('Pasta')+#$0301
    会得到 enter image description here

我想到的所有基于常量的语法的总结:

AccentAcute: WideString =            #$0301;   //works
AccentAcute: WideString =   WideChar(#$0301);  //works
AccentAcute: WideString = WideString(#$0301);  //works
AccentAcute: WideString =             $0301;   //incompatble types
AccentAcute: WideString =    WideChar($0301);  //works
AccentAcute: WideString =  WideString($0301);  //invalid typecast

AccentAcute: WideChar =            #$0301;     //fails, gives Pasta´
AccentAcute: WideChar =   WideChar(#$0301);    //fails, gives Pasta´
AccentAcute: WideChar = WideString(#$0301);    //incompatible types
AccentAcute: WideChar =             $0301;     //incompatible types
AccentAcute: WideChar =    WideChar($0301);    //fails, gives Pasta´
AccentAcute: WideChar =  WideString($0301);    //invalid typecast

重新排列WideChar可以工作,只要你仅附加到一个变量上

//Works
t := '0123401234012340123';
t := t+WideChar(#$D840);
t := t+WideChar(#$DC00);

//fails
t := '0123401234012340123'+WideChar(#$D840);
t := t+WideChar(#$DC00);

//fails
t := '0123401234012340123'+WideChar(#$D840)+WideChar(#$DC00);

//works
t := '0123401234012340123';
t := t+WideChar(#$D840)+WideChar(#$DC00);

//works
t := '';
t := t+WideChar(#$D840)+WideChar(#$DC00);

//fails; gives junk
t := ''+WideChar(#$D840)+WideChar(#$DC00);

//crashes compiler
t := WideString('')+WideChar(#$D840)+WideChar(#$DC00);

//doesn't compile
t := WideChar(#$D840)+WideChar(#$DC00);

一定要克服编译器的无意义错误;对未经全面测试的情况进行全面测试。是的,我知道David,我们应该升级。


本质上来说,Delphi 5 不适合进行 Unicode 开发。 :-) - Warren P
希望这些废话只是限于编译器读取我的源代码文件的能力。一旦我设置了超出基本多语言平面(BMP)的字符的单元测试数据生成和代理对的测试,所有这些问题都应该得到解决。 - Ian Boyd
那时候 Delphi 5 还是相当过时的! - Warren P
David Heffernan 在这方面可以帮到你。 - Ian Boyd

2
这在Delphi 5/7中可行:
var
  test: WideString;
begin

   test := WideChar($0061);
   test := test + WideChar($0301);

   MessageBoxW(0, PWideChar(test), 'Character with diacratic', MB_ICONINFORMATION or MB_OK);
end;

简而言之:
  • In delphi 5 and delphi 7, it does not appear that concatenating WideChars to WideString works using #$xxxx form literals.
  • # doesn't seem to work as you'd expect for unicode literals.

  • You can't just add two or more widechars in a single expression, like this:

    test := WideChar(a)+WideChar(b);  // won't compile in D5/D7.
    

'string' + WideChar($xxxx) 语法在 'Pasta'+WideChar($0301); 中失败了。它生成的是 Pasta´,而不是 Pastá - Ian Boyd
Ian,你不能使用'ansistring'字面量并仅将WideChars附加到它们上面!在Delphi 5中尝试这样做似乎对我来说很疯狂。 - Warren P
你为什么认为'string'AnsiString?编译器在编译期间可以将其视为WideString - Ian Boyd
只要你在现有的字符串后追加,就可以在单个表达式中添加多个“WideChar”:t := t+WideChar(#$D840)+WideChar(#$DC00);t := t+WideChar($D840)+WideChar($DC00); - Ian Boyd
在我们思考将等效的连接拆分开来的基础上,我发现了更多可行和不可行的情况。最终,我发现最好的解决方法总是使用变量或常量进行连接。 - Ian Boyd

0

你试过 #$0301#$0061(即带重音符号的字母)了吗?

好的。

所以在这个版本中,#$.... 只处理 ASCII 8 位常量。

你可以使用内存级别的解决方法:

type
    TWordArray  = array[1..MaxInt div SizeOf(word)-2] of word;
    // start at [1], just as WideStrings
    // or: TWordArray  = array[0..MaxInt div SizeOf(word)-1] of word;
    PWordArray = ^TWordArray;

var
  test: WideString;
begin
  test := '12'; // or SetLength(test,2);
  PWordArray(test)[1] := $61; 
  PWordArray(test)[2] := $301;
  MessageBoxW(0, pointer(test), 'Character with diacratic', MB_ICONINFORMATION or MB_OK);
end;

这将始终有效,因为您不会使用字符/宽字符等进行操作。

并且在Delphi的Unicode版本中也将按预期工作。


我尝试过了,并更新了问题。我预计它不会起作用,因为没有“前一个”字符可以应用于变音符号。 - Ian Boyd
2
问题在于 # 仅适用于 ASCII 码点(61 没问题,但 $301 大于 $FF,所以不行)在 Delphi 5 中。 - Warren P
在Delphi中,您可以使用#$xxxx语法;它对我有效(请参见上文),在VirtualTreeview(VirtualTrees.pas)和Jedi(JclUnicode.pas)中也有效。我遇到的错误似乎围绕编译器对它们的不同形式的解释而发生。但是,在基本层面上,语法ThreeEighths: WideString = #$215C;是被接受的。 - Ian Boyd
@Ian 为了避免 Delphi 版本之间的 #$.... 不一致性,使用直接内存访问字是安全和快速的。 PWordArray(test) [] 访问是安全且快速的。 - Arnaud Bouchez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接