有没有一种工具可以从Delphi表单文件中提取所有的SQL命令字符串?

9

为了文档和进一步检查,我想在许多项目中对所有DFM文件运行“提取字符串”以找到所有的SQL语句。是否有命令行工具可以做到这一点?所有的DFM文件都是文本格式。


1
我猜"DFM"文件是Delphi版本的资源文件,这个猜测正确吗? - lexu
@lexu 是的,它们包含了“表单”、“框架”和“数据模块”的布局和绑定信息。 - mjn
@lexe 但我不知道它们是否最终会成为二进制文件中的普通应用程序资源 - mjn
是的,它们确实存在,但如果我没记错的话,它们作为资源类型 RC_DATA 存在。Delphi 内部会转换成实际的窗体和其他对象。 - Ken White
5个回答

2
根据您所使用的查询组件的类型,我想您可以在项目文件夹上使用命令行grep(或其他任何文本搜索工具)来完成这个操作。对于普通的TQuery类似组件,在DFM中,你将会有如下所示的内容:
   SQL.Strings=( 'select * from mytable' )
或者也可能是(我手边没有Delphi来检查,这就是在家的乐趣!)
   SQL.Text=( 'select * from mytable' )
考虑到这些字符串可能会在DFM中跨越几个“行”,并且可能有几个变化需要进行检查,个人建议编写一个小的Delphi程序来完成此操作。
基本思路是:迭代给定目录中的所有文件/子文件夹,查找所有DFM文件,并为每个文件读入一个TStringList,在其中检查您感兴趣的任何TQuery(SQL)属性,并将结果(组件名称、文件名、实际SQL字符串)写入结果文件。最多不应该超过一两个小时的工作时间。
如果您有存储过程,使用的不是TQuery类型的组件调用,您将首先需要检查DFM中SQL的外观方式;它可能类似于
   CommandText=( 'exec mysproc :id, :value' )
等等。
编辑: 根据评论中的讨论,以下是我DFM中的一个示例:
所以我只需要找到 SQL.Strings = (这一部分,然后读取剩余的行和所有后续行,去除每行开头和结尾的',直到到达以')'结尾的行 - 在这一点上,我就完成了。实际上,在每行引号中包含的SQL(和注释)并不重要。您想要阅读每个感兴趣的行,并剪切出每行第一个和最后一个引号之间的文本。这必须有效,因为我无法看到Delphi以其他方式处理此数据流,它不可能“读取”字符串内容 - 它仅基于以下原则工作:字符串列表(可能)已被分成几行,DFM中每行都用一个开放和关闭的'进行定界,并且整个字符串列表的内容都包含在一对括号中。
这有意义吗,还是我还是错过了什么? :-)

SQL命令可以包含括号(和注释(包括(和))),因此解析会有一些困难,因为)也终止了SQL字符串...如果SQL文本包含注释或字段值中的特殊字符,那么Unicode怎么办呢?但我想那将是有趣且容易的部分:P - mjn
非常正确...但是如果你从第一个 ' 开始解析,并在进行过程中计算你所处的引用层数,那么你应该没问题。最终,Delphi DFM 解析器必须能够理解字符串,使其以引号开头和结尾。SQL 文本不能包含 Unicode,除非 DFM 文件本身是 Unicode(除非我对 DFM 中的字符串有什么误解!),因此您可以先测试是否为 Unicode 文件 - 我在 SO 上有一些代码,可以检查文件是否为 Unicode。就像你说的,这都是乐趣的一部分! :-) - robsoft
Delphi不是很理想,除非您使用RegExp库。我建议编写一个PERL脚本来解析DFM并提取SQL。我曾经做过类似的事情,将TTable / TQuery组件转换为DOA“等效”组件,并且在修改文件时需要保持pas和dfm同步。用正确的工具完成工作。在这种情况下,需要使用具有良好正则表达式实现的脚本语言。 PERL可能不适合您,但您应该能够找到自己喜欢的Python,Ruby之类的语言。 - mcottle
1
@robsoft:一个简单的/* :-) */会破坏计数,注释也需要正确处理。而且SQL注释语法并不标准化。也许将Delphi的流式代码复制到读取DFM中会更容易? - mjn
@mjustin - 很好的观点,我昨晚也在考虑这个问题。但我认为每行始终都以'开头和结尾,因此你只需要从SQL.Text=('开始的位置获取文本,并从所有后续字符串中删除前导和尾随的',直到获得不以'开头的字符串为止-这将是下一个属性或组件的开始。然后你只需要记得删除最后一个字符串上的闭合括号即可。现在我越想越觉得,如果你开始解析SQL,你就会迷失方向! :-) - robsoft
@mjustin - 我已经编辑了我的答案,包括一些来自DFM的代码。我99.9%确定不需要解析字符串本身,只需剪切每行相关内容的开头和结尾引号即可。 :-) - robsoft

2
这是来自Felix Colibri的DFM解析器。 DFM解析器 这是一个有趣的工具,用于处理此类任务。 YACC

范围:Delphi 1到2005版适用于Windows,Kylix。我认为它不兼容Unicode。 - none

1
我已经创建了自己的DFM解析器,使用RAD Studio和我所在公司的600个源文件进行了测试。该解析器是用Go语言编写的。

https://github.com/gonutz/dfm

你可以使用它来解析DFM文件,并递归地检查内存中的对象,查找类型为dfm.String的属性。

0

由于 DFM 基本上是以 名称=值 的格式存在,因此您可以将其加载到 tStringlist 中,然后循环遍历每一行,查找您感兴趣的特定属性名称:

var
  slDfm : tStringList;
  Item : String;
  ix : integer;
begin
  slDFM := tStringlist.create;
  try
    slDFM.LoadFromFile( filename );
    for ix := 0 to slDfm.Count-1 do
      begin
        slDfm.Strings[ix] := Trim(slDfm.Strings[ix]);
        if SameText(Trim(slDfm.Names[ix]),'CommandText') then
          memo1.Lines.Add('"'+Trim(slDfm.ValueFromIndex[ix])+'"');
      end;
  finally
    slDFM.free;
  end;
end;

0
非常感谢您的回答!我将尝试另一种解决方案,即在“GNU Gettext for Delphi and C++ Builder”中包含的“提取字符串”工具。
.po文件不仅包括所有组件文本,还包括所有资源字符串(另一个存储SQL命令的地方),完整地引用了来源(哪个pas或dfm文件,哪个组件属性名称),并且它已经是一个非常简单的“name=value”列表。
有了.po文件,很容易从.pas文件中分离出所有SQL.Text和所有名称为“SQL_...”的资源字符串。

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