【问题标题】:Making a character variable equal to a nill value in delphi在delphi中使字符变量等于空值
【发布时间】:2013-08-27 08:07:47
【问题描述】:

我正在创建一个程序,我在其中搜索字符串中的元音,找到它们后,需要从字符串中删除元音。

 mystring := 'August'   ;

{if mystring[1] IN ['A','E','I','O','U'] ;}
for k := 1 to length(mystring) DO
BEGIN
if mystring[K] IN ['a','e','i','o','u']
then mystring[k] := ''

但是错误

不兼容的类型:出现'Char'和'String'"

如何从字符串中删除元音?

【问题讨论】:

  • 空字符串'' 不是字符。这是,嗯,空字符串。您使用的是哪个版本的 Delphi?你能在你的问题中添加一个 Delphi 版本标签吗?
  • @Alexandr 不,不要那样做。想想当您将字符串放入编辑控件时会发生什么。
  • 我会使用我最喜欢的pointer char technique :-) [我知道很多人讨厌它]
  • @TLama 好的,我不喜欢它——当我们将产品从 Delphi 7 迁移到 XE 时,我仍然受到这样的代码的创伤,XE 要么比无指针版本慢,要么有问题(带有unicode)或只是不可读(通常是这些的组合)。
  • @Stefan,它永远是你的选择。是的,它的可读性较差,但它与 ANSI/Unicode 兼容。你刚才写得不好。

标签: delphi char


【解决方案1】:

您正在寻找的是一个 null 字符值。您正在尝试使用空字符串,它是一个长度为零的实体。但是没有长度为零的字符。您要查找的 null 字符值根本不存在。

查看这一点的另一种方法是考虑循环末尾的 Length(mystring) 是什么。无论您使用mystring[k] := ... 分配什么字符,mystring 的长度都不会被修改。

因此,您可以创建一个新字符串而不是修改现有字符串。例如:

var 
  new: string;
  len: Integer;
....
SetLength(new, Length(mystring));
len := 0;
for i := 1 to Length(mystring) do
begin
  if not (mystring[i] in ['a','e','i','o','u']) then
  begin
    inc(len);
    new[len] := mystring[i];
  end;
end;
SetLength(new, len);
mystring := new;

或者您可以反复拨打StringReplace

mystring := StringReplace(mystring, 'a', '', [rfReplaceAll]);
mystring := StringReplace(mystring, 'e', '', [rfReplaceAll]);
//etc. 

这个使用StringReplace的版本比第一种方法慢。

另一种方法是就地操作:

var 
  len: Integer;
....
len := 0;
for i := 1 to Length(mystring) do
begin
  if not (mystring[i] in ['a','e','i','o','u']) then
  begin
    inc(len);
    mystring[len] := mystring[i];
  end;
end;
SetLength(mystring, len);

【讨论】:

    【解决方案2】:

    或者这个:

    VAR
      I : Cardinal;
    
    BEGIN
      I:=1;
      WHILE I<=LENGTH(MyString) DO
        IF MyString[I] IN ['a','e','i','o','u','A','E','I','O','U'] THEN
          DELETE(MyString,I,1)
        ELSE
          INC(I)
    END;
    

    David 的代码可能更快,但这个不需要任何额外的字符串。此外,它还处理大写元音(如果你想要的话)。

    【讨论】:

    • 每次调用Delete时都需要一个额外的字符串
    • 真的吗?编译器似乎效率低下。我会原地移动字符(如果引用计数 = 1)。编译器的优化空间,那么……
    【解决方案3】:

    只是对您的评估的另一个建议:

    for i := 1 to Length(mystring) do
      if mystring[i] in ['a', 'e', 'i', 'o', 'u'] then
        mystring[i] := #1;
    mystring := StringReplace(mystring, #1, '', [rfReplaceAll]);
    

    想法是用字符 #1 替换所有元音(#0 不起作用)。循环就是这样做的。然后,字符串中的所有 #1 都被一个空字符串替换掉,这由 StringReplace 函数实现。

    【讨论】:

      【解决方案4】:

      你可以这样做:

      localStr:=mystring;
      mystring:='';
      if ... then mystring:=mystring+localStr[i];
      

      例子

      mystring:= 'August';
      ...
      
      var
      localStr: string;
      i       : Integer;
      begin
      localStr:=mystring;
      mystring:='';
      for i := 1 to Length(localStr) do if NOT ((localStr[i] in ['a','e','i','o','u'])) then
                    mystring:=mystring+localStr[i];
      end;
      

      结果我的字符串:Agst


      专家:

      没想到只有一个标志的StringReplace 这么慢。
      如果字符串是 474000 字节。此测试需要 2 分 5 秒。

      User        Code in short
      --------------------------------------------
      
      David       inc(len) | new[len] := mystring[i] | SetLength(new, len)
      David 2.    inc(len) | mystring[len] := mystring[i] | SetLength(mystring, len)
      TLama       if not (C^ in CharSet) then | localStr[I] := C^ | Inc(I)
      Me          localStr:=mystring | mystring:='' | mystring:=mystring+localStr[i]
      AlexSc      mystring := StringReplace(mystring, #1, '', [rfReplaceAll])
      HeartWare   I := 1                  | WHILE I<=LENGTH(MyString) DO  | DELETE(MyString,I,1) | INC(I)
       " DEC(I)   I := LENGTH(MyString)   | WHILE I > 0 DO                | DELETE(MyString,I,1) | DEC(I)
      

      HeartWare DEC(I) 只是为了表明 delete downto 更快

      几秒钟内的测试。

                  length(mystring)--MB--------------------
                  0.474       1.049       4.002       7.995       15.358      56.948
      ----------------------------------------------------                
      Delphi 5 on XP
      ----------------------------------------------------            
      TLama   :   0.003       0.016       0.047       0.078       0.172       0.687
      David   :   0.003       0.016       0.047       0.093       0.192       0.765
      David 2.:   0.003       0.016       0.063       0.109       0.219       0.875
      
      Me      :   0.125       0.281       1.109       2.192       4.203
      HeartWare:  27.284      131.057
       " DEC(I):  21.793      108.406
      AlexSc  :   143.723     break > 8 min.
      
      Rad XE4 on vista
      ----------------------------------------------------            
      TLama   :   0.003       0.032       0.068       0.139       0.194
      David   :   0.003       0.032       0.068       0.146       0.203
      Me      :   0.094       0.172       0.481       0.921       1.576
      HeartWare:  23.056      119.076
       " DEC(I):  17.519      103.319
      AlexSc  :   125.082     break > 8 min.
      

      【讨论】:

      • @TLama :测试了你的代码,它有点慢。 (短版CharSet = ['a', 'e', 'i', 'o', 'u'];
      • 大卫的第二个条目(就地)怎么样?我猜这个是最快的(与他的第一个条目相差很小)。
      • @HeartWare:1. 条目,mystring = 0.474 MB。 2.进入mystring = 1.049 MB.
      • @moskito-x,有趣的基准测试!我认为指针字符迭代不再更快(更长的时间)。我不知道为什么,但我就是喜欢它……但无论如何,我想我已经找到了我可能会浪费时间的根源。试试this version。有了那个版本,我必须赢 :-) 只是不要忘记缩短字符集,因为我还要检查大写字母。 [+1ed]
      • @moskito-x,奇怪的是CharInSet 函数如何减慢执行速度。还是谢谢!
      猜你喜欢
      • 1970-01-01
      • 2016-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-04
      • 2011-12-10
      • 1970-01-01
      相关资源
      最近更新 更多