You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求可解析printf格式说明符的Delphi源码以实现多语言格式校验

实现Delphi下printf格式说明符的校验方案

核心思路:基于Delphi RTL源码改造

Delphi的RTL(运行时库)中SysUtils.pas文件里的Format系列函数(如WideFormat)包含完整的printf格式说明符解析逻辑,你可以直接提取改造,无需从零开发。以下是具体实现步骤:

1. 提取并改造格式符解析逻辑

从SysUtils.pas中剥离格式符解析的核心代码,封装成独立的格式符提取函数,能识别完整的格式说明符(包括标志位、宽度、精度、类型字符):

type
  TFormatSpec = record
    FullSpec: string; // 完整格式符,如'%10.2f'
    TypeChar: Char;   // 类型标识,如'd'/'s'/'f'
  end;
  TFormatSpecList = array of TFormatSpec;

function ExtractPrintfFormatSpecs(const AStr: string): TFormatSpecList;
var
  I: Integer;
  SpecStart: Integer;
  CurrentSpec: string;
begin
  SetLength(Result, 0);
  I := 1;
  while I <= Length(AStr) do
  begin
    if AStr[I] = '%' then
    begin
      SpecStart := I;
      Inc(I);
      // 处理转义的%%
      if (I <= Length(AStr)) and (AStr[I] = '%') then
      begin
        Inc(I);
        Continue;
      end;
      // 跳过标志位、宽度、精度等前缀
      while (I <= Length(AStr)) and (AStr[I] in ['-', '+', '0', ' ', '#', '1'..'9', '.']) do
        Inc(I);
      // 提取完整格式符(包含类型字符)
      if (I <= Length(AStr)) and (AStr[I] in ['d', 'i', 'u', 'x', 'X', 'f', 'e', 'E', 'g', 'G', 'c', 's', 'p', 'n']) then
      begin
        CurrentSpec := Copy(AStr, SpecStart, I - SpecStart + 1);
        SetLength(Result, Length(Result) + 1);
        Result[High(Result)].FullSpec := CurrentSpec;
        Result[High(Result)].TypeChar := AStr[I];
        Inc(I);
      end
      else
        Inc(I); // 无效格式符,直接跳过
    end
    else
      Inc(I);
  end;
end;

2. 实现原串与翻译串的格式符校验

通过对比两个字符串提取出的格式符列表,判断一致性:

  • 先检查列表长度是否一致
  • 再逐个对比对应位置的格式符(可选择严格匹配完整规格,或仅匹配类型字符)
function AreFormatSpecsMatching(const ASrcStr, ADestStr: string): Boolean;
var
  SrcSpecs, DestSpecs: TFormatSpecList;
  I: Integer;
begin
  SrcSpecs := ExtractPrintfFormatSpecs(ASrcStr);
  DestSpecs := ExtractPrintfFormatSpecs(ADestStr);
  
  // 先校验数量是否一致
  Result := Length(SrcSpecs) = Length(DestSpecs);
  if not Result then Exit;
  
  // 逐个校验格式符(这里用严格匹配完整规格,若只需类型一致可替换为TypeChar对比)
  for I := 0 to High(SrcSpecs) do
  begin
    if SrcSpecs[I].FullSpec <> DestSpecs[I].FullSpec then
    begin
      Result := False;
      Exit;
    end;
  end;
end;

3. 适配C++ printf的扩展格式符

如果需要兼容C++特有的格式符(如%lld、%zu),只需扩展类型字符的判断逻辑:

// 修改类型判断部分的代码
if (I <= Length(AStr)) then
begin
  // 处理长整型格式符
  if AStr[I] = 'l' then
  begin
    Inc(I);
    if (I <= Length(AStr)) and (AStr[I] in ['d', 'i', 'u', 'x', 'X']) then
    begin
      CurrentSpec := Copy(AStr, SpecStart, I - SpecStart + 1);
      SetLength(Result, Length(Result) + 1);
      Result[High(Result)].FullSpec := CurrentSpec;
      Result[High(Result)].TypeChar := AStr[I];
      Inc(I);
      Continue;
    end;
  end
  // 处理size_t类型的%zu
  else if (AStr[I] = 'z') and (I+1 <= Length(AStr)) and (AStr[I+1] = 'u') then
  begin
    CurrentSpec := Copy(AStr, SpecStart, 3);
    SetLength(Result, Length(Result) + 1);
    Result[High(Result)].FullSpec := CurrentSpec;
    Result[High(Result)].TypeChar := 'u';
    Inc(I, 2);
    Continue;
  end
  // 标准类型判断
  else if AStr[I] in ['d', 'i', 'u', 'x', 'X', 'f', 'e', 'E', 'g', 'G', 'c', 's', 'p', 'n'] then
  begin
    CurrentSpec := Copy(AStr, SpecStart, I - SpecStart + 1);
    SetLength(Result, Length(Result) + 1);
    Result[High(Result)].FullSpec := CurrentSpec;
    Result[High(Result)].TypeChar := AStr[I];
    Inc(I);
  end
  else
    Inc(I);
end;

注意事项

  • 不同Delphi版本的RTL逻辑可能略有差异,建议直接查看对应版本SysUtils.pas的Format实现,确保提取的解析逻辑准确。
  • 若需要支持更多C++扩展格式符,可根据printf规范继续扩展类型判断分支。

内容的提问来源于stack exchange,提问作者alancc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 06:00:19