【问题标题】:Why doesn't TPageProducer remove quotation marks from strings?为什么 TPageProducer 不从字符串中删除引号?
【发布时间】:2013-06-12 08:59:23
【问题描述】:

我正在尝试调试仅在我的大型应用程序(在 XE3 中运行良好)在使用 XE4 编译后运行时才出现的行为。该问题似乎导致一些引用的字符串(例如“MyString”)即使在 Web.HTTPProd 中的 TPageProducer 被“取消引用”后仍保留其引用。例如,考虑下面的代码,它是从这个 Delphi 源单元 Web.HTTPApp 的一小部分摘录:

procedure ExtractHeaderFields(Separators, _WhiteSpace: TSysCharSet; Content: PChar;
  Strings: TStrings; Decode: Boolean; StripQuotes: Boolean = False);
{$ENDIF NEXTGEN}
var
  Head, Tail: PChar;
  EOS, InQuote, LeadQuote: Boolean;
  QuoteChar: Char;
  ExtractedField: string;
{$IFNDEF NEXTGEN}
  WhiteSpaceWithCRLF: TSysCharSet;
  SeparatorsWithCRLF: TSysCharSet;
{$ENDIF !NEXTGEN}

  function DoStripQuotes(const S: string): string;
  var
    I: Integer;
    InStripQuote: Boolean;
    StripQuoteChar: Char;
  begin
    Result := S;
    InStripQuote := False;
    StripQuoteChar := #0;
    if StripQuotes then
    begin
      for I := Result.Length - 1 downto 0 do
        if Result.Chars[I].IsInArray(['''', '"']) then
          if InStripQuote and (StripQuoteChar = Result.Chars[I]) then
          begin
            Result.Remove(I, 1);
            InStripQuote := False;
          end
          else if not InStripQuote then
          begin
            StripQuoteChar := Result.Chars[I];
            InStripQuote := True;
            Result.Remove(I, 1);
          end
    end;
  end;

我在使用 TPageProducer 时看到了这个调用,我可以看到我的良好源字符串进入上面的 ExtractHeaderFields 例程,然后进入“DoStripQuotes”函数。进入 DoStripQuotes 并观看“结果”表明它不会改变,即使调用 Result.Remove (以剥离报价)。当我将此“DoStripQuotes”例程用于一个简单的测试应用程序时,它不会编译,告诉我“Result.anything”是不允许的。我假设结果,虽然它被定义为“字符串”,但它必须是 Web.HTTPProd 上下文中的另一种类型的字符串。

所以我开始想,这可能与我听说过的“不可变字符串”有关。我读到了这个SO question,虽然我明白了要点,但我可以提供更实用的建议。

具体来说,我想回答以下问题:

  1. 如果允许使用表示法 Result.Length,什么类型的“字符串”是“结果”?
  2. 有没有一种方法可以告诉编译器对单元使用“XE3”兼容性? (这可能让我看到问题出在哪里)。我试过 {$ZEROBASEDSTRINGS ON} / OFF 但这似乎会造成更多混乱,我不知道我在做什么!

感谢您的帮助。

稍后编辑:正如在下面接受的答案中指出的,这是 VCL 单元 Web.HTTPApp.pas 中的一个错误,它应该在第 2645 行周围的两个地方读取“Result := Result.Remove(I,1)”,而不是"Result.Remove(I,1)"

【问题讨论】:

    标签: string delphi delphi-xe4


    【解决方案1】:

    如果允许使用表示法 Result.Length,什么类型的“字符串”是“结果”?

    它只是旧的string,别名为UnicodeString,自Delphi 2009 以来您一直在使用它。不同之处在于这段代码使用了新的记录助手(特别是SysUtils.TStringHelper)。这就是让您可以在字符串变量上使用 . 表示法的原因。

    有没有办法告诉编译器对单元使用“XE3”兼容性?

    没有。有问题的代码是一个库单元,它旨在以特定模式编译。更重要的是,除非你自己编译 RTL/VCL,否则你不能轻易地重新编译它。即使有这样的模式,也无济于事,因为代码完全是错误的(见下文)。再多的模式切换都无法修复这段特定的代码。

    我开始想,这可能与我听说过的不可变字符串有关。

    不是。 Delphi 编译器都没有不可变的字符串。不可变字符串的概念只是作为未来变化浮出水面的东西。如果进行了更改,预计将首先在移动编译器中进行。


    问题实际上只是您发布的代码中的一个相当简单的错误,显然根本没有经过测试。使用Remove 是错误的。该方法不会就地修改字符串。相反,它返回一个删除了字符的新字符串。代码应为:

    Result := Result.Remove(I, 1);
    

    编写ExtractHeaderFields 的开发者犯这个错误的原因是设计字符串助手代码的人错误地命名了Remove 方法。因为Remove 是一个动词,你会期望它就地操作。一个不修改主题并返回一个新实例的方法,就像这个方法一样,应该被命名为一个名词。所以这个方法应该命名为Remnants。在我看来,RTL 设计者似乎复制了同样存在缺陷的 .net 命名。

    您应该提交一份 QC 报告(如果尚不存在)。我知道 XE4 更新 1 刚刚发布。它包含一个修复程序是合理的。

    在我看来,您的其他选择是:

    1. 坚持使用 XE3,直到 XE4 得到充分调试。
    2. 在您的项目中包含Web.HTTPApp 单元的副本并自行修复错误。

    【讨论】:

    • 你是绝对正确的,大卫,就是这样——德尔福的 Web.HTTPApp 中的一个错误,它遗漏了对结果的分配。也感谢您的教程。
    • 质检报告已提交。我稍后会检查这是否在更新 #1 中得到修复。
    • 忽略函数结果时似乎没有用于警告的编译器选项。在这种情况下,甚至应该引发编译器错误(假设可以选择使用这样的指令标记TStringHelper)。
    • @LURD IIRC 您不能忽略原始 Pascal 中的函数结果,但扩展语法会改变这种行为。编译器警告将非常有价值。遗憾的是,许多 Emba 库代码的质量都很低。
    • @All 我可以确认这在更新 #1 中没有修复。
    猜你喜欢
    • 1970-01-01
    • 2017-09-17
    • 2015-09-14
    • 1970-01-01
    • 2013-06-06
    • 2021-12-12
    • 2022-01-01
    • 2011-05-12
    • 2015-04-27
    相关资源
    最近更新 更多