2Pascal-新时代的Pascal

标题: 字符串 编码 和 跨平台 讨论 01 [打印本页]

作者: wang_80919    时间: 2015-6-4 17:10
标题: 字符串 编码 和 跨平台 讨论 01
var
  str: string;
begin
  str[Low(str) + 从 0 开始的编号]  //保证跨平台。
end;

str.xxx 函数 从 0 开始。例如  str.IndexOf()
xxx(str) 这种函数,如果是 以前就有的 从 1 开始。例如 Pos(str)


有关 DLL 字符串 的 建议 看看 第 9 楼 和 第 17 楼。
当然,其他楼也要看看。

作者: wang_80919    时间: 2015-6-4 17:11
移动平台下
没有 Char WideChar AnsiChar PChar PWideChar PAnsiChar  了。只有 Byte TBytes 。
建议用  TEncoding.XXXX 来处理和 string 的转换。
例如

str := TEncoding.UTF8.GetString(你的Bytes);

AnsiBytes := TEncoding.ANSI.GetBytes(str);


关键是 使用 TEncoding TBytes PByte string 这几种类型 综合使用。
即可跨平台了。

当然, TNetEncoding 里头也有一些 函数是支持  Tbytes 的。
例如
TNetEncoding.Base64.DecodeStringToBytes(sKey+'=');
也有反过来的版本
接收用的TBytes := TNetEncoding.Base64.Encode(TBytes变量);


在任何情况下,都禁止用 XXXXToYYYY、UTF8Encode 和 UTF8Decode 这些旧的函数。因为全都不如 TEncodiing.编码.函数 这种准确。
使用 TEcnding 的时候,一定要指定编码,否则跨平台会效果不一致。


D7 的 string 默认是 Ansistring ,同时你可以强迫他成为 Utf8String。

高版本的 string 是 UnicodeString,为了安全起见,不要去想他是什么编码,你应该当成无编码的。中性的。(这是重点)
需要编码的时候,就该 TBytes 出场了。
用 TEncoding 来完成 string 和 Tbytes 的 转换即可。
作者: wang_80919    时间: 2015-6-4 17:17
MarshaledAString 和 TBytes 可以互相强制转换。
但是 MarshaledAString 一般是以 #0 结尾的。当然也可能不是。
但是 TBytes 是个数组,所以是有大小的。有时候,内容很大,有效内容却不大。

所以,尽量不要乱转换。
确定他们的大小再说。

作者: OneChen    时间: 2015-6-5 17:15
Delphi String 常用字串符处理函数
[attach]846[/attach]
来源:http://www.cnblogs.com/onechen/p/4555139.html

作者: gaoyong_gy    时间: 2015-6-12 09:57
delphi TStringList 用法详解

//TStringList 常用方法与属性 :
var
List: TStringList;
i: Integer;
begin
List := TStringList.Create;
List.Add('Strings1'); {添加}
List.Add('Strings2');
List.Exchange(0,1); {置换}
List.Insert(0,'Strings3'); {插入}
i := List.IndexOf('Strings1'); {第一次出现的位置}
List.Sort; {排序}
List.Sorted := True; {指定排序}
List.Count; {总数}
List.Text; {文本集合}
List.Delete(0); {删除, 0是第一个数据}
List.LoadFromFile('c:/tmp.txt');{打开}
List.SaveToFile('c:/tmp.txt'); {保存}
List.Clear; {清空}
List.Free; {释放}
end;





//读入字符串
var
List: TStringList;
begin
List := TStringList.Create;
List.CommaText := 'aaa,bbb,ccc,ddd';
//相当于: List.Text := 'aaa' + #13#10 + 'bbb' + #13#10' + 'ccc' + '#13#10' + 'ddd';

ShowMessage(IntToStr(List.Count)); //4
ShowMessage(List[0]); //aaa

List.Free;
end;



//置换分隔符
var
List: TStringList;
begin
List := TStringList.Create;
List.Delimiter := '|';
List.DelimitedText := 'aaa|bbb|ccc|ddd';

ShowMessage(IntToStr(List.Count)); //4
ShowMessage(List[0]); //aaa

List.Free;
end;



//类似的哈希表操作法
var
List: TStringList;
begin
List := TStringList.Create;

List.Add('aaa=111');
List.Add('bbb=222');
List.Add('ccc=333');
List.Add('ddd=444');

ShowMessage(List.Names[1]); //bbb
ShowMessage(List.ValueFromIndex[1]); //222
ShowMessage(List.Values['bbb']); //222

//ValueFromIndex 可以赋值:
List.ValueFromIndex[1] := '2';
ShowMessage(List[1]); //bbb=2

//可以通过 Values 赋值:
List.Values['bbb'] := '22';
ShowMessage(List[1]); //bbb=22

List.Free;
end;

//避免重复值
var
List: TStringList;
begin
List := TStringList.Create;

List.Add('aaa');

List.Sorted := True; //需要先指定排序
List.Duplicates := dupIgnore; //如有重复值则放弃

List.Add('aaa');

ShowMessage(List.Text); //aaa

//Duplicates 有3个可选值:
//dupIgnore: 放弃;
//dupAccept: 结束;
//dupError: 提示错误.

List.Free;
end;


//排序与倒排序
{排序函数}
function DescCompareStrings(List: TStringList; Index1, Index2: Integer): Integer;
begin
Result := -AnsiCompareText(List[Index1], List[Index2]);
end;

procedure TForm 1.Button1Click(Sender: TObject);
var
List: TStringList;
begin
List := TStringList.Create;

List.Add('bbb');
List.Add('ccc');
List.Add('aaa');

//未排序
ShowMessage(List.Text); //bbb ccc aaa

//排序
List.Sort;
ShowMessage(List.Text); //aaa bbb ccc

//倒排序
List.CustomSort(DescCompareStrings); //调用排序函数
ShowMessage(List.Text); //ccc bbb aaa

//假如:
List.Sorted := True;
List.Add('999');
List.Add('000');
List.Add('zzz');
ShowMessage(List.Text); //000 999 aaa bbb ccc zzz
end;
作者: wang_80919    时间: 2015-6-12 12:46
顶楼上,总结的不错。
TStringList 是最好用的工具。
作者: OneChen    时间: 2015-6-16 08:10
字串处理别忘了还有官方建议的 TStringBuilder

http://docwiki.embarcadero.com/L ... tils.TStringBuilder
作者: wang_80919    时间: 2015-6-16 09:00
还有更难懂的
TMarshal

TMarshaller

作者: wang_80919    时间: 2015-7-2 09:25
TMarshaller.AsRaw 可以返回 MarshaledAString,但是编码不确定。
如果你确保对方需要的是 UTF8 编码的字符串,可以使用 AsUtf8().ToPointer 来返回 MarshaledAString,MarshaledAString(TMarshaller.Asutf8(你的字符串).ToPointer);
如果对方需要的是 UTF8 的,也可以 MarshaledAString(Utf8Encode(你的字符串)); 来返回。
如果你需要的是 PANSICHAR 的。可以使用
AsAnsi().ToPointer 来返回。

下面是用 TMarshaller 的写法。

var
  M : TMarshaller;
  A: PAnsiChar;
  U: PUTF8Char;
  MAA: MarshaledAString;
  MAU: MarshaledAString;
begin
  A := M.AsAnsi('你的字符串' ).ToPointer;
  U := M.AsUtf8('你的字符串' ).ToPointer;
  MAA := MarshaledAString(TMarshaller.AsAnsi('你的字符串' ).ToPointer);
  MAU := MarshaledAString(TMarshaller.AsUtf8('你的字符串' ).ToPointer);
end;


下面是用 TEncoding 的写法。
var
  A: PAnsiChar;
  W: PWideChar;
  U: PUTF8Char;
begin
  A := Addr(TEncoding.ANSI.GetBytes('你的字符串' + #0)[0]);
  W := Addr(TEncoding.Unicode.GetBytes('你的字符串' + #0)[0]);
  U := Addr(TEncoding.UTF8.GetBytes('你的字符串' + #0)[0]);
end;
作者: wang_80919    时间: 2015-7-24 13:41
delphi 2010升级到xe8后,decodestring汉字出现:No mapping for the
http://www.2pascal.com/forum.php ... =1692&fromuid=4
(出处: 2Pascal-新时代的Pascal)


大家可以看看这个问题的解决。
作者: wang_80919    时间: 2015-8-5 18:30
[迁安]Nightmourn(328783896)  18:29:51
@[北京]老猫 Android转换gb2312 urlencode要怎么百度…

[北京]老猫(1765535979)  18:30:45
@[迁安]Nightmourn 此问题在中文 DELPHI 开发界(对于你们这些不懂得自己研究的人来说)尚属首次 研究,百度没有收录。

答案就是 使用 TNetEncdong.Url.Encode(TBytes 版本的参数); (很早之前,我们自己研究出的答案)

如何获取 TBytes 的结果,前面已经讨论过了。


作者: soguifan    时间: 2015-8-6 15:59
本帖最后由 soguifan 于 2015-8-7 08:28 编辑

[mw_shl_code=delphi,false]
Edit1.Text :='提交';
Edit2.Text:=httpencode(edit1.Text) ; //UTF8 urlencode结果为  %E6%8F%90%E4%BA%A4
Edit3.Text:=Tnetencoding.URL.Encode(edit1.Text);//UTF8 urlencode结果为  %E6%8F%90%E4%BA%A4
//Edit4.Text :=Tnetencoding.url.EncodeBytesToString( Tencoding.GetEncoding(936).getbytes(edit1.Text));//错误No mapping for the Unicode character exists in the target multi-byte code page.
//Edit4.Text :=Tnetencoding.url.encode(Tencoding.ansi.GetString(Tencoding.GetEncoding(936).getbytes(edit1.Text)));//UTF8 urlencode结果为  %E6%8F%90%E4%BA%A4
//请问怎么在Android显示GB2312结果为%cc%e1%bd%bb
[/mw_shl_code]



作者: wang_80919    时间: 2015-8-6 18:40
楼上的问题,太过低级,前面的讨论 综合一下,就是答案。
作者: wang_80919    时间: 2015-8-7 09:31
  Input: TBytes;

  SetLength(Output, SM4_BLOCKSIZE);
  FillChar(Input[0], SM4_BLOCKSIZE, 0);

不能 FillChar(Input,

会发生非法操作。
作者: soguifan    时间: 2015-8-10 09:35
本帖最后由 soguifan 于 2015-8-10 09:36 编辑
wang_80919 发表于 2015-8-7 09:31
Input: TBytes;

  SetLength(Output, SM4_BLOCKSIZE);

本人不是学计算机的,工作也与计算机无关,Delphi只是业余爱好而已。wang_80919(Flying Wang)大神所说的“太过低级”的问题,看了上边的讨论[答案就是 使用 THttpEncdong.Url.Encode(TBytes 版本的参数); (很早之前,我们自己研究出的答案)],本人菜鸟还是没看明白,THttpEncdong也不知道是什么东东,最后自己写了个函数,完成了汉字转GB2312 Urlencode。[mw_shl_code=delphi,false]
function MyUrlEncode(const input: string): string; // 汉字转Gb2312 urlencode
var
  S: string;
  Stream: TStringStream;
  B: Byte;
begin
  Result := '';
  S := '';
  try
    Stream := TStringStream.Create(input, TEncoding.GetEncoding(936));
    for B in Stream.Bytes do
      S := Format('%s%%%.2x', [S, B]);
  finally
    Stream.Free;
  end;
  Result := S;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Edit1.Text := '提交';
  Edit2.Text := MyUrlEncode(Edit1.Text); // 结果  %cc%e1%bd%bb
end;
[/mw_shl_code]


作者: wang_80919    时间: 2015-8-10 12:10
浪费时间
你直接说找不到 THTTPEncdong
不就得了。

主要是我英文太差 不记得正确的 类名
TNetEncdong。

作者: wang_80919    时间: 2015-8-27 17:59
http://bbs.2ccc.com/topic.asp?topicid=496558
大家可以看看这个帖子。
调用 DLL。也可以使用 TEncoding

function GetVerifyCode(fileName: PByte; strsn: PByte; var strCode: PByte): BOOL; stdcall; external 'GetVerifyCode.dll';

procedure TForm1.Button1Click(Sender: TObject);
var
  aFile, aSn, aCode: string;
  PFile,PSn, PCode: PByte;
  ACodes: TBytes;
begin
  aFile := 'verify_code.bin';
  aSn := '535727843';
  PFile := addr(TEncoding.ANSI.GetBytes(aFile)[0]);  //建议 GetBytes(aFile + #0)
  PSn := addr(TEncoding.ANSI.GetBytes(aSn)[0]);  //建议 GetBytes(aSn + #0)
  SetLength(ACodes, 6); //ANSI 是 6 Unicode 是 6*2。//建议多留一个字符的空间,用于存放 #0
  PCode := addr(ACodes[0]);
  if GetVerifyCode(PFile, PSn, PCode) then
  begin
    aCode := TEncoding.ANSI.GetString(ACodes);
    ShowMessage(aCode);
  end
  else
  begin
    ShowMessage('获取密码失败!');
  end;
end;
作者: wang_80919    时间: 2015-9-11 11:51
对于 StringList 可以设置 读取文件 或者 读取流的 TEncoding。保存也是。
AStringList.Loadxxxxx(xxx,TEncoding.XXXX);
AStringList.Savexxxxx(xxx,TEncoding.XXXX);

还可以设置 换行的格式。
AStrignList.LineBreak := #$0A;  这是 MAC IOS 安卓下 通用的,但是 WIN 下就不行了。 所以,建议大家改为 #$0D#$0A 。这个所有平台都是回车换行。

类似于 Memo 的控件 Lines Items  都是 TStringList 。都可以自己控制读取或保存的 字符编码。
作者: wang_80919    时间: 2015-11-2 17:17
如果 需要输入一个 PWideChar
TMarshal.InString  即可。




欢迎光临 2Pascal-新时代的Pascal (http://2pascal.com/) Powered by Discuz! X3