现有 Delphi 项目迁移到 Tiburon 中的注意事项

delphi7可用类型转换 delphi7可用BytesOf,StringOf转换 立即下载

随着 Embarcadero 8 月 25 号发布 RAD Studio 2009 (Tiburon) 以来(Tiburon 的 RTM 日期可能要延后到 9 - 10 月),随着 Tiburon 全面支持 Unicode,现有的 Delphi / C++ Builder 项目要迁移到 Unicode 下应该注意些什么也成为大家最为关心的问题。Tiburon 对 Unicode 的支持不仅仅是将原来 类型映射为 AnsiString 的 String 类型直接改成 WideString,而是对 AnsiString 结构作出修改,同时增加了 UnicodeString 类型来完美支持 Unicode。这意味着,要想平稳迁移到 Unicode 下,程序员不得不对现有代码作出一定的修改。

在 Tiburon 以前的版本中,AnsiString 和 WideString 除了 data size 不同外,在功能上是相同的。早先版本的 AnsiString 的结构如下:

Format of AnsiString Data Type  

Reference Count  
Length  
String Data (Byte sized)  
Null Term 
-8  
-4  
0  
Length  


而这个结构在 Tiburon 中已经发生变化,AnsiString 增加了两个新的 fields, 一个是 CodePage,一个是 ElemSize,这样做可以让新版的 AnsiString 和 UnicodeString 在结构上保持一致。

而 WideString 类型在早先的版本中用来保存双字节数据。其本质和 Windows BSTR 是一样的。在 Tiburon 中 WideString 仍然是为 COM 保持兼容的,也就是说它依然没有引用计数,相比较而言,UnicodeString 在性能和效率上将会是 COM 以外的程序首选的字符类型。

闪亮登场的 UnicodeString 类型

Tiburon 中,新的、默认的 string 就是 UnicodeString。这个类型既可以包含 ANSI 字符,也可以包含 Unicode 字符。下面是 UnicodeString 类型的结构:

Format of UnicodeString Data Type  

CodePage 
Element Size 
Reference Count  
Length  
String Data (element sized)  
Null Term 
-12  
-10  
-8  
-4  
0  
Length * elementsize  


UnicodeString 和 AnsiString 都是如上的结构,尽管 UnicodeString 包含是双字节数据,AnsiString 包含的是单字节的。

用 Object Pascal 语言来描述 UnicodeString 的结构,应该是这样:

type
 StrRec = record
   CodePage: Word;
   ElemSize: Word;
   refCount: Integer;
   Len: Integer;
   case Integer of
     1: array[0..0] of AnsiChar;
     2: array[0..0] of WideChar;
 end;

UnicodeString 增加了 code page 字段和 element size 来描述字符串内容,这使得 UnicodeString 和其它类型的字符串可以很好的相兼容,所以 AnsiString 和 UnicodeString 可以很方便的互相转换,唯一要注意的是,当把 UnicodeString 向下转型到 AnsiString 的时候,可能会丢失数据,因此强烈建议你不要这么做。UnicodeString 保存的是 UTF-16 字符。

在旧的环境下,可以使用编译标志 Unicode 来判断编译环境是否支持 UnicodeString,以便您可以在同一套代码中维护不同版本的字符支持环境。编译指令如下:

Delphi 使用:
    {$IFDEF Unicode}
C++ Builder 使用:
   
 #ifdef _DELPHI_STRING_UNICODE

变化概要:

  • String 类型映射为 UnicodeString 而不是 AnsiString
  • Char 类型映射为 WideChar(2 bytes not 1 byte), 并且是 UTF-16 字符
  • PChar 类型映射为 PWideChar
  • C++ 中,System::String 映射到 UnicodeString 类
  • Delphi 中,AnsiString 映射为早先版本中默认的 string

未变化概要:

  • AnsiString
  • WideString
  • AnsiChar
  • PAnsiChar
  • 隐式转换仍然可用
  • 用户的活动页代码(The user's active code page)控制着模式(ANSI vs. Unicode),所以 AnsiString 仍然可以支持

由于这些变化,代码编写上也出现了一些值得注意的情况,特别是在你打算将旧有的项目迁移到 Tiburon 下时更是如此。下面就列出一些发生的变化情况以及编写代码时应该注意的注意事项。

下面的操作将不再依赖字符 Size:

  • 合并字符串
    • +
    • +
    • +
    • Concat( , )
  • 标准字符串函数
    • Length()返回字符元素的长度,此值可能和字符在字节长度上并不匹配。SizeOf 函数则返回数据的字节长度,这意味着 SizeOf 和 Length 的返回值可能是不同的
    • Copy(, , )返回的 SubString 基于字符元素
    • Pos(,)返回第一个字符元素的序号
  • 操作
    • CompareStr()
    • CompareText()
    • ...
  • FillChar()
    • FillChar(Rect, SizeOf(Rect), #0)
    • FillChar(WndClassEx, SizeOf(TWndClassEx), #0). 使用的时候注意 WndClassEx.cbSize := SizeOf(TWndClassEx)
  • Windows API
    • API 默认使用 WideString (*W)形态的版本
    • PChar()具有相同的语义

范例:

GetModuleFileName:
function ModuleFileName(Handle: HMODULE): string;
var
  Buffer: array[0..MAX_PATH] of Char;
begin
  SetString(Result, Buffer, GetModuleFileName(Handle, Buffer, Length(Buffer)));
end;

GetWindowText:
function WindowCaption(Handle: HWND): string;
begin
  SetLength(Result, 1024);
  SetLength(Result, GetWindowText(Handle, PChar(Result), Length(Result)));
end;

字符串索引:
function StripHotKeys(const S: string): string;
var
  I, J: Integer;
  LastChar: Char;
begin
  SetLength(Result, Length(S));
  J := 0;
  LastChar := #0;
  for I := 1 to Length(S) do
  begin
    if (S[I] <> '&') or (LastChar = '&') then
    begin
      Inc(J);
      Result[J] := S[I];
    end;
    LastChar := S[I];
  end;
  SetLength(Result, J);
end;


接上文

依赖字符 Size 的代码结构:

在 Tiburon 中,下列列表中列出的这些函数和特性依赖字符 Size,并且已经包含了一个“轻便”的版本,迁移代码的时候只需要将列出的代码迁移到后面提供的轻便版本即可。

  • SizeOf() 替换为 Length()
范例:
var
  Count: Integer;
  Buffer: array[0..MAX_PATH - 1] of Char;
begin
  // 现有代码 - 当 string = UnicodeString 的时候这段代码是错的
  Count := SizeOf(Buffer);
  GetWindowText(Handle, Buffer, Count);
               
  // 正确的应该是下面这样
  Count := Length(Buffer); // <<-- Count 应该是 Chars 而不是 Bytes
  GetWindowText(Handle, Buffer, Count);
end;
SizeOf 返回的是数组的字节数,而 GetWindowText 的 Counts 参数需要的是字符数,所以这里需要把 SizeOf 换成 Length。
  • Move(... CharCount) 替换为 Move( ,,, CharCount * SizeOf(Char))
var
   Count: Integer;
   Buf1, Buf2: array[0..255] of Char;
begin
  // 现有代码 - 当 string = UnicodeString (char = 2 bytes) 时,下面的代码是错误的
  Count := Length(Buf1);
  Move(Buf1, Buf2, Count);
  
  // 正确的写法应该是
  Count := SizeOf(Buf1);                // <<-- Specify buffer size in bytes
  Count := Length(Buf1) * SizeOf(Char); // <<-- Specify buffer size in bytes
  Move(Buf1, Buf2, Count);
end;
由于 Length 返回的是字符数,而 Move 的 Count 参数需要的是字节数,所以应该用 SizeOf 或者 Length(Buf1) * SizeOf(Char) 替换 Length(Buf1)。
  • Stream 的 Read/Write 替换为 AnsiString, SizeOf(Char),或者使用 TEncoding 类
调用 Read/ReadBuffer 方法的范例:
var
  S: string;
  L: Integer;
  Stream: TStream;
  Temp: AnsiString;
begin
  // 现有代码- 当 string = UnicodeString 时它是不正确的
  Stream.Read(L, SizeOf(Integer));
  SetLength(S, L);
  Stream.Read(Pointer(S)^, L);
  
  // 正确的 Unicode 写法如下
  Stream.Read(L, SizeOf(Integer));
  SetLength(S, L);
  Stream.Read(Pointer(S)^, L * SizeOf(Char));  // <<-- Specify buffer size in bytes
  
  //正确的 Ansi 写法如下
  Stream.Read(L, SizeOf(Integer));
  SetLength(Temp, L);              // <<-- 使用临时的变量 AnsiString
  Stream.Read(Pointer(Temp)^, L * SizeOf(AnsiChar));  // <<-- Specify buffer size in bytes
  S := Temp;                       // <<-- 放宽 string 到 Unicode
end;
上面的解决方案依赖于您存储在 Stream 中的字符串的编码格式,更好的读取和转换他们建议使用 TEncoding 类。

调用 Write/WriteBuffer 的范例:
var
  S: string;
  Stream: TStream;
  Temp: AnsiString;
begin
  // 现有代码 - 当 string = UnicodeString 时它是错的
  Stream.Write(Pointer(S)^, Length(S));
  
  // 正确的读取 Unicode 的代码
  Stream.Write(Pointer(S)^, Length(S) * SizeOf(Char)); // <<-- Specify buffer size in bytes
  
  // 正确的读取 Ansi 的代码
  Temp := S;          // <<-- Use temporary AnsiString
  Stream.Write(Pointer(Temp)^, Length(Temp) * SizeOf(AnsiChar));// <<-- Specify buffer size in bytes
end;
上面的解决方案依赖于您要存储进 Stream 中的字符串的编码格式,建议使用 TEncoding 类来更好的对格式进行处理。
  • FillChar(, , ) 如果采用 #0 填充, 替换为  * SizeOf(Char);如果填充其它字符,替换为 StringOfChar 函数
范例:
var
  Count: Integer;
  Buffer: array[0..255] of Char;
begin
   // 现有代码 - 当 string = UnicodeString ( char = 2 字节) 时,这段代码是错的
   Count := Length(Buffer);
   FillChar(Buffer, Count, 0);
               
   // 正确的代码应该写作下面这样
   Count := SizeOf(Buffer);                // <<-- Specify buffer size in bytes
   Count := Length(Buffer) * SizeOf(Char); // <<-- Specify buffer size in bytes
   FillChar(Buffer, Count, 0);
end;
Length 返回的是字符数,而 FillChar 的 Count 参数需要的是字节数,所以必须用 SizeOf 替换 Length,或者使用 Length * SizeOf(Char)。

另外,需要注意的是,Tiburon 中 Char 等于 2 个字节,FillChar 填充的时候确是按照 Bytes 来计算的,所以,下面的代码

var
  Buf: array[0..32] of Char;
begin
  FillChar(Buf, Length(Buf), #9);
end;

并不是向目标中填充 $09,而是 $0909,要得到正确的数值,应该改写成下面这样:

var
  Buf: array[0..32] of Char;
begin
  StrPCopy(Buf, StringOfChar(#9, Length(Buf)));
...
end;
  • GetProcAddress(, ) 
由于 GetProcAddres 没有对应的 *W (Unicode) 版本的 API,所以只能使用下面的代码来正确调用它:
procedure CallLibraryProc(const LibraryName, ProcName: string);
var
  Handle: THandle;
  RegisterProc: function: HResult stdcall;
begin
  Handle := LoadOleControlLibrary(LibraryName, True);
  @RegisterProc := GetProcAddress(Handle, PAnsiChar(AnsiString(ProcName)));
end;
  • RegQueryValueEx 函数
由于 RegQueryValueEx 函数的 Len 指定的是字节数,而不是字符数,所以 Unicode 版本中它的大小是实际需要大小的 2 倍,所以这样的代码:

Len := MAX_PATH;
if RegQueryValueEx(reg, PChar(Name), nil, nil, PByte(@Data[0]), @Len) = ERROR_SUCCESS
then
  SetString(Result, Data, Len - 1) // Len includes #0
else
  RaiseLastOSError;

应该换成下面这样:

Len := MAX_PATH * SizeOf(Char);
if RegQueryValueEx(reg, PChar(Name), nil, nil, PByte(@Data[0]), @Len) = ERROR_SUCCES
then
  SetString(Result, Data, Len div SizeOf(Char) - 1) // Len includes #0, Len contains the number of bytes
else
  RaiseLastOSError;
  • CreateProcessW 函数
在 Unicode 版本的 CreateProcess 函数中,其行为和 ANSI 的版本略有不同。Unicode 的 CreateProcessW 会改变参数 lpCommandLine 传入的数据,因此调用 CreateProcess / CreateProcessW 的时候,不可以给 lpCommandLine 赋值常量,或者是一个变量指向的常量,否则函数会抛出 access violations 的异常。下面是错误的代码:

// 传入了一个 string 常量
CreateProcess(nil, 'foo.exe', nil, nil, False, 0,
  nil, nil, StartupInfo, ProcessInfo);

// 传入了一个常量表达式
  const
    cMyExe = 'foo.exe'
  CreateProcess(nil, cMyExe, nil, nil, False, 0,
    nil, nil, StartupInfo, ProcessInfo);

// 传入了一个引用计数为 -1 的字符串:
const
  cMyExe = 'foo.exe'
var
  sMyExe: string;
  sMyExe := cMyExe;
  CreateProcess(nil, PChar(sMyExe), nil, nil, False, 0, nil, nil, StartupInfo, ProcessInfo);
  • LeadBytes 常量
早先的版本中 LeadBytes 常量包含了本地系统中所有可以作为双字节字符 LeadByte 的列表,常常有这样的代码:
if Str[I] in LeadBytes then

现在你需要将它改成调用 IsLeaderChar 函数
if IsLeadChar(Str[I]) then
  • 使用 TMemoryStream 类
当您需要用 TMemoryStream 写入一个文本文件的时候,最好在写入任何字符数据进去之前先写入一个 Byte Order Mark (BOM):
var
  Bom: TBytes;
begin
  ...
  Bom := TEncoding.UTF8.GetPreamble;
  Write(Bom[0], Length(Bom));

而任何写入的字符需要被转换成 UTF-8 编码:
var
  Temp: Utf8String;
begin
  ...
  Temp := Utf8Encode(Str); // Str 是要写入文件的字符
  Write(Pointer(Temp)^, Length(Temp));
 //Write(Pointer(Str)^, Length(Str)); 原来写入字符串的代码


接上文

  • MultiByteToWideChar 函数
调用 Windows API MultiByteToWideChar 函数可以简单的用一个任务替代,下面是一个是用 MultiByteToWideChar 的例子:

procedure TWideCharStrList.AddString(const S: string);
var
  Size, D: Integer;
begin
  Size := SizeOf(S);
  D := (Size + 1) * SizeOf(WideChar);
  FList[FUsed] := AllocMem(D);
  MultiByteToWideChar(0, 0, PChar(S), Size, FList[FUsed], D);
  Inc(FUsed);
end;

转换到 Unicode 下可以写作这样(同时支持 Unicode 和 ANSI 字符):

procedure TWideCharStrList.AddString(const S: string);
{$IFNDEF UNICODE}
var
  L, D: Integer;
{$ENDIF}
begin
{$IFDEF UNICODE}
  FList[FUsed] := StrNew(PWideChar(S));
{$ELSE}
  L := Length(S);
  D := (L + 1) * SizeOf(WideChar);
  FList[FUsed] := AllocMem(D);
  MultiByteToWideChar(0, 0, PAnsiChar(S), L, FList[FUsed], D);
{$ENDIF}
  Inc(FUsed);
end;
  • SysUtils.AppendStr 函数
AppendStr 函数已经废弃了,因为它与 AnsiString 硬编码在一起,而且没有 Unicode 的版本可以替换,所以下面的代码

AppendStr(String1, String2);

应该换成:

String1 := String1 + String2;

您也可以使用新的 TStringBuilder 类来替换。
  • 使用 Named Threads
现有 Delphi 代码中使用了 Named Threads 的代码必须修改了。在早先的版本中,当你需要在分类(gallery)中用一个新的 Thread Object 去创建一个 Thread 的时候,需要在新的 Thread 单元中建立下面的类型:

type
TThreadNameInfo = record
  FType: LongWord; // must be 0x1000
  FName: PChar; // pointer to name (in user address space)
  FThreadID: LongWord; // thread ID (-1 indicates caller thread)
  FFlags: LongWord; // reserved for future use, must be zero
end;

在调试器中,Named Thread 的处理器期待 FName 成员是 ANSI 字符,不是 Unicode,所以上面的声明必须改成下面这样:

type
TThreadNameInfo = record
  FType: LongWord; // must be 0x1000
  FName: PAnsiChar; // pointer to name (in user address space)
  FThreadID: LongWord; // thread ID (-1 indicates caller thread)
  FFlags: LongWord; // reserved for future use, must be zero
end;

在新版本中上述声明已经修改,提示这段代码是需要您注意早先版本中您手工创建并声明的代码需要您自己修改。

如果您需要在 Named Thread 中使用 Unicode 字符,您必须将字符串格式化成 UTF-8 编码,调试器可以完全支持改编码。例如:

ThreadNameInfo.FName := UTF8String('UnicodeThread_фис');

注意:C++ Builder 里面一直使用的是正确的代码,所以上述问题在 C++ Builder 中并不存在。
  • 使用 PChar 转换的指针运算
在 Tiburon 更早的版本中,并不是所有的指针类型都支持指针运算。因为这样,为了让无类型指针也支持指针运算,许多代码都将其转化成 PChar 操作。现在,可以使用 Tiburon 中的新编译条件 {$POINTERMATH} 来指示编译器允许指针运算,特别是允许 PByte 的指针运算。{$POINTERMATH ON/OFF} 可以打开/禁止对任意指针变量的运算,增减指针实际操作的是指针元素的大小。

下面的例子是一个将某类型指针转换成 PChar 后的指针运算:

function TCustomVirtualStringTree.InternalData(Node: PVirtualNode): Pointer;
begin
  if (Node = FRoot) or (Node = nil) then
    Result := nil
  else
    Result := PChar(Node) + FInternalDataOffset;
end;

您应该将其修改成 PByte 而不是 PChar:

function TCustomVirtualStringTree.InternalData(Node: PVirtualNode): Pointer;
begin
  if (Node = FRoot) or (Node = nil) then
    Result := nil
  else
    Result := PByte(Node) + FInternalDataOffset;
end;

在上面的例子中,Node 真实的数据不是 PChar 的数据。将其强制转换成 PChar 的操作在早先的版本中是正常的,因为早先版本中
 SizeOf(Char) == Sizeof(Byte)。但是现在不同了,所以这样的代码必须从 PChar 改换成 PByte。如果不做这样的更改,返回的 Pointer 将指向错误的数据。 
  • 变体开放数组(Variant Open Array)参数
如果你的代码中有使用 TVarRec 类型去处理开放数组的话,你可能需要为其添加对 vtUnicodeString 的支持。参看下列示例:

procedure RegisterPropertiesInCategory(const CategoryName: string;
  const Filters: array of const); overload;
var
I: Integer;
begin
  if Assigned(RegisterPropertyInCategoryProc) then
    for I := Low(Filters) to High(Filters) do
      with Filters[I] do
        case vType of
          vtPointer:
            RegisterPropertyInCategoryProc(CategoryName, nil,
              PTypeInfo(vPointer), );
          vtClass:
            RegisterPropertyInCategoryProc(CategoryName, vClass, nil, );
          vtAnsiString:
            RegisterPropertyInCategoryProc(CategoryName, nil, nil,
              string(vAnsiString));
          vtUnicodeString:
            RegisterPropertyInCategoryProc(CategoryName, nil, nil,
              string(vUnicodeString));
        else
          raise Exception.CreateResFmt(@sInvalidFilter, [I, vType]);
        end;
 end;
  • 其他需要注意的代码:
    • AllocMem(
    • AnsiChar
    • of AnsiChar
    • AnsiString
    • of Char
    • Copy(
    • GetMem(
    • Length(
    • PAnsiChar(
    • Pointer(
    • Seek(
    • ShortString
    • string[
代码中包含上述写法的地方可能需要修改以适应 UnicodeString 的变化。


带字符的集合类型

您可能需要修改下列类型:

  • in AnsiChar> 这样的代码生成的程序是正确的(>#255 的字符不会包含在集合内)。编译器会提出 "WideChar reduced in set operations" 的警告,基于您代码的需要,您可以关闭这个警告,或者使用 CharInSet 函数替代。
  • in LeadBytes 全局的 LeadBytes 变量包含的是本地 MBCS Ansi 字符的集合。UTF-16 格式也有 LeadChar 的概念((#$D800 - #$DBFF 是高 surrogate, #$DC00 - #$DFFF 是低 surrogate)。因此建议使用 overload 函数 IsLeadChar 来判断,该函数的 ANSI 版本检测 LeadBytes,WideChar 版本检测 high/low surrogate。
  • 字符分类 使用静态类 TCharacter。Character 单元中提供了一些函数对字符分类:IsDigit, IsLetter,IsLetterOrDigit, IsSymbol, IsWhiteSpace, IsSurrogatePair,等等。

应当心这些结构

您需要检查下列可能引起错误的结构:

  • 模糊的类型转换
    • AnsiString(Pointer(foo))
    • 检查正确性:代码是什么意图?
  • 可疑的类型转换引发的警告
    • PChar()
    • PAnsiChar()
  • 直接建立、操作、访问 string 的内部结构。例如 AnsiString 的内部结构已经发生变化,所以这样的操作是危险的。您应该使用 StringRefCount, StringCodePage, StringElementSize 等方法来获得额外信息。

控件和类

  • TStrings: 内部存储的是 UnicodeStrings。
  • TWideString:(可能被废弃)没有更改,内部使用 WideString (BSTR)
  • TStringStream
    • 被重写成内部存储 ANSI 字符
    • 字符编码可以被重载
    • 考虑使用 TStringBuilder 替代 TStringStream 来逐步构建字符串
  • TEncoding
    • Default 属性是用户活动页码(users’ active code page)
    • 支持 UTF-8
    • 支持 UTF-16, big 和 little endian
    • 支持 Byte Order Mark (BOM)
    • 您可以继承子类实现特殊的编码

Byte Order Mark

BOM 必须添加到文件中以便判断文件的编码方式。

  • UTF-8 使用 EF BB EF
  • UTF-16 Little Endian 使用 FF FE
  • UTF-16 Big Endian 使用 FE FF

做好这些注意事项,将帮助您顺利地把旧有项目迁移到 Tiburon 的 Unicode 下。当然,如果您开发的是多版本控件,或者是希望项目能在多个版本中编译,您最好根据这些特性定义适当的编译条件,以便让代码更好的被更低的版本的编译器支持和编译。

本文基于 Tiburon 帮助编写,如有翻译错误或描述不准确的地方欢迎大家指正!

Anaconda下安装LabelImg 阅读详情

相关推荐

Wezterm的安装和简单配置

希望 wezterm 的主题配色,保持和 powershell 默认配色一致,也就是 Compell 主题。目的是在频繁使用 wezterm 时,原本的根据颜色判断文件信息(尤其是WSL里的Linux下,文件和目录颜色)依然可以使用。wezterm 默认用 cmd.exe, 我是 win11,希望默认用 powershell。

baiyu33的博客 4271

字符串函数大全

代码 uses StrUtils;【字符串函数大全】 首部 function AnsiResemblesText(const AText, AOther: string): Boolean; $[StrUtils.pas 功能 返回两个字符串是否相似 说明 ANSI(American National Standards Institut...

weixin_30872671的博客 267

MT4/MT5数据源接入全攻略:从买服务、自研API到低成本DDE,哪种方案适合你?

本文全面解析MT4/MT5数据源接入的三种主流方案:商业服务、自研API和低成本DDE,详细对比其技术参数、成本结构和适用场景。帮助技术团队根据业务需求选择最优方案,确保外汇交易系统的数据流稳定性和实时性,提升交易体验和业务连续性。

weixin_42568801的博客 173

delphi activex 函数返回值

你要把Return   Type设为HRESULT,然后加一个Parameter如下 ReturnVal   BSTR   *   [out,retval]

supersyd的专栏 1788

UE4项目迁移指南:如何无缝导入外部.uasset文件并保持材质关联

本文详细解析了将外部.uasset文件无缝导入UE4项目的专业方法。针对手动复制文件时常见的材质关联丢失问题,提供了使用引用查看器进行诊断和修复的实用技巧,并推荐使用引擎内置的“迁移”功能确保资源依赖关系的完整性,帮助开发者高效整合项目资源。

t8u9v0的博客 1046

探索Python融合地学:一文解决osgeo库安装失败问题

总结一下,要安装osgeo模块,关键在GDAL依赖库的安装,如果能够顺利安装GDAL依赖库,因其是osego的模块,因此osgeo的部分模块也能够得到自动安装,此时再运行代码,发现代码并不报错,能够正常运行了。第一步,我们要安装imagecodecs库,它支持多种常见的图像格式,当然也包含我们的目标tif格式,为方便后续的图像处理和安装osgeo模块,先安装此库。目前GDAL已经更新到了3.10版本,这里主要看你的Python版本是上面,小编用的是Python3.13,电脑是64位的,因此,我们选择。

Promising_GEO的博客 5461

delphi php des,delphi 支持UNICODE的DES加密

//聲明:這個是在網上下載下來之後,加入了UNICODE的處理部份//在D7和D2010中測試通過unit U_DES;interfaceusesSysUtils, Variants,strutils;typeTKeyByte = array[0..5] of Byte;TDesMode = (dmEncry, dmDecry);//加密function EncryStr(const Str: S...

weixin_34293588的博客 308

PCL学习笔记(四)——点云曲面重建

文章目录一、凸包算法二、 单纯的点云数据固然很好,但仅仅是点的话仍是不够的,因为这不利于我们后续对实体对象的渲染与各种应用,如计算实体的表面积、体积等等,所以这就需要我们对实体进行点云的曲面重建。 一、凸包算法 在计算机图形学中,凸包是指在任意维空间中包含某一有限点集P的最小凸集,它由凸包顶点构成,在二维上其表现形式为一个凸多边形,而在三维上则表现为一个凸多面体。在二维层面上来讲,最常用的凸包算法有Graham扫描法和Jarvis卷包裹法,但前者并不适用于三维层面,后者倒是可以扩展到三维。除此之外,在

dayuhaitang1的博客 6912

RAD Studio 10.4.1关于Rest应用中字符串的编码解码及delphi处理html乱码问题

目录 RAD Studio 10.4.1关于Rest应用中字串符的编码解码及html乱码问题 一、与www相关的编码与解码方法 1.1、System.NetEncoding.pas 1.1.1、TNetEncoding.Base64格式 1.1.2、TNetEncoding.HTML格式 1.1.3、TNetEncoding.URL格式 1.2、Web.HTTPApp.pas 1.3、IdStrings.pas 1.4、关于网页html乱码 二、进制转化 2.1、16进制string.

pulledup的博客 1558

D16: OpenClaw + Notion API:知识管理新玩法

本文介绍了如何利用OpenClaw连接Notion API构建自动化知识管理系统。文章首先分析了传统知识管理的痛点,包括信息分散、更新不及时等问题,并对比了Notion与其他工具在API完整性、结构化程度等方面的优势。接着详细说明了Notion API的获取和授权流程,并设计了包含项目知识库、技术决策库和会议纪要库的三层架构系统。最后通过会议纪要自动归档的实战案例,展示了如何通过YAML配置实现从飞书会议到Notion的自动化知识沉淀流程。该方案能有效解决团队知识管理中的信息碎片化问题,提升协作效率。

刘一说的IT专栏 274

A算法的蒙特卡洛树搜索

A*算法的蒙特卡洛树搜索 作者:禅与计算机程序设计艺术 1. 背景介绍 在人工智能和游戏开发领域,搜索算法是一个非常重要的研究方向。其中A算法和蒙特卡洛树搜索是两种广泛应用的经典算法。A算法是一种启发式搜索算法,通过评估各个节点到目标节点的启发式代价来引导搜索方向,在

AI天才研究院 1744

现有 Delphi 项目迁移到 Delphi 2009(Tiburon) 中的注意事项

转自:http://cnpack.org/showdetail.php?id=598&amp;lang=zh-cn 现有 Delphi 项目迁移到 Tiburon 中的注意事项 翻译:峪飞鹰 2008-08-30 随着 Embarcadero 8 月 25 号发布 RAD Studio 2009 (Tiburon) 以来(Tiburon 的 RTM 日期可能要延后到 9 -...

javatoyou 192

选型不再靠感觉:一文看懂 SAP Event Mesh 与 SAP Integration Suite, advanced event mesh 的能力边界

本文对比分析了SAP Event Mesh与SAP Integration Suite, advanced event mesh的差异。SAP Event Mesh适合轻量级场景,主要用于SAP系统间异步通信,支持AMQP、MQTT等协议,消息大小限制为1MB。而advanced event mesh面向企业级事件网络,提供跨云/本地部署、事件治理、监控等高级功能,支持30MB消息和更大存储容量。选择时需考虑业务规模、实时性要求、治理需求等因素:单一SAP生态内扩展可选Event Mesh;跨区域、多云环境

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 133

Delphi 项目迁移到 Tiburon(Delphi2009,Delphi2010) 中的注意事项

Delphi 项目迁移到 Tiburon(Delphi2009,Delphi2010) 中的注意事项 翻译:现有 Delphi 项目迁移到 Tiburon 中的注意事项 CnPack 开源软件项目  2008-08-31 16:45:05<br /><br />现有 Delphi 项目迁移到 Tiburon 中的注意事项 <br />翻译:峪飞鹰<br />2008-08-30 <br />随着 Embarcadero 8 月 25 号发布 RAD Studio 2009 (Tiburon) 以来(Tib

月亮宝石的天空 1420

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

现有 Delphi 项目迁移到 Tiburon 中的注意事项[转]

现有 Delphi 项目迁移到 Tiburon 中的注意事项 翻译:峪飞鹰随着 Embarcadero 8 月 25 号 发布 RAD Studio 2009 (Tiburon) 以来(Tiburon 的 RTM 日期可能要延后到 9 - 10 月),随 着 Tiburon 全面支持 Unicode,现有的 Delphi / C++ Builder 项目要迁移到 Unicode 下...

weixin_30772105的博客 105

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

现有Delphi项目迁移到Tiburon delphi2009中的注意事项

随着 Embarcadero 8 月 25 号发布 RAD Studio 2009 (Tiburon) 以来(Tiburon 的 RTM 日期可能要延后到 9 - 10 月),随着 Tiburon 全面支持 Unicode,现有的 Delphi / C++ Builder 项目要迁移到 Unicode 下应该注意些什么也成为大家最为关心的问题。Tiburon 对 Unicode 的支持不仅仅是将原

GaryYuan 迟来的博客 1187

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

转:现有 Delphi 项目迁移到 Delphi 2009(Tiburon) 中的注意事项

转自:http://cnpack.org/showdetail.php?id=598&lang=zh-cn 现有 Delphi 项目迁移到 Tiburon 中的注意事项 翻译:峪飞鹰 2008-08-30 随着 Embarcadero 8 月 25 号发布 RAD Studio 2009 (Tiburon) 以来(Tiburon 的 RTM 日期可能要延后到 9 - ...

weixin_30673715的博客 133
上一篇: Delphi 日期时间函数
下一篇: Delphi面向对象:overload与override
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值