Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String Delphi函数,用于测试位置x处的字符串_String_Delphi_Delphi 6 - Fatal编程技术网

String Delphi函数,用于测试位置x处的字符串

String Delphi函数,用于测试位置x处的字符串,string,delphi,delphi-6,String,Delphi,Delphi 6,在最近一个涉及通过串行链接接收字符串的应用程序中,我发现自己编写了如下代码: if (pos('needle', haystack) = 1) then ... 以检查特定子字符串是否处于字符串的乞讨状态 我突然意识到pos函数并不适用于此,因为它不知道我要寻找的子字符串位于哪个位置 有没有一个好的函数可以做到这一点 是否有一个更一般化的函数,如IsSubStringAtneedle、haystack、position 我确实想过使用这样的东西: function IsSubstrAt(con

在最近一个涉及通过串行链接接收字符串的应用程序中,我发现自己编写了如下代码:

if (pos('needle', haystack) = 1) then ...
以检查特定子字符串是否处于字符串的乞讨状态

我突然意识到pos函数并不适用于此,因为它不知道我要寻找的子字符串位于哪个位置

有没有一个好的函数可以做到这一点

是否有一个更一般化的函数,如IsSubStringAtneedle、haystack、position

我确实想过使用这样的东西:

function IsSubstrAt(const needle, haystack: string; position: Integer): Boolean;
var
  ii: integer;
begin
  result := true;
  for ii := 1 to length(needle) de begin
    if (haystack[poition + ii -1] <> needle[ii]) then begin
      result := false;
      break;
    end;
  end;
end;
进行一些错误检查


我希望找到一个现成的答案。

因为您只想查看一个位置,所以您只需形成子字符串并测试它。像这样:

function IsSubStringAt(const needle, haystack: string; position: Integer): Boolean;
var
  substr: string;
begin
  substr := Copy(haystack, position, Length(needle));
  Result := substr = needle;
end;
如果性能非常关键,那么您可能希望在不创建副本的情况下就地执行比较,从而执行堆分配。你可以用AnsiStrLComp来做这个

function IsSubStringAt(const needle, haystack: string; position: Integer): Boolean;
begin
  if Length(haystack) - position + 1 >= Length(needle) then begin
    Result := AnsiStrLComp(
      PChar(needle), 
      PChar(haystack) + position - 1, 
      Length(needle)
    ) = 0;
  end else begin
    Result := False;
  end;
end;

如果要在不区分大小写的情况下进行检查,请在第一个版本中将=替换为SameText,并在第二个版本中将AnsiStrLComp替换为AnsiStrLComp。

因为您只想查看一个位置,所以可以形成子字符串并对其进行测试。像这样:

function IsSubStringAt(const needle, haystack: string; position: Integer): Boolean;
var
  substr: string;
begin
  substr := Copy(haystack, position, Length(needle));
  Result := substr = needle;
end;
如果性能非常关键,那么您可能希望在不创建副本的情况下就地执行比较,从而执行堆分配。你可以用AnsiStrLComp来做这个

function IsSubStringAt(const needle, haystack: string; position: Integer): Boolean;
begin
  if Length(haystack) - position + 1 >= Length(needle) then begin
    Result := AnsiStrLComp(
      PChar(needle), 
      PChar(haystack) + position - 1, 
      Length(needle)
    ) = 0;
  end else begin
    Result := False;
  end;
end;

如果要在不区分大小写的情况下进行检查,请在第一个版本中将=替换为SameText,并在第二个版本中将AnsiStrLComp替换为AnsiStrLComp。

因为XE7可以使用假设位置是基于1的:

function IsSubStringAt(const needle, haystack: string; position: Integer): Boolean;
begin
  result := string.Compare(hayStack, position-1, needle, 0, needle.Length) = 0;
end;

由于XE7,您可以使用假设位置是基于1的:

function IsSubStringAt(const needle, haystack: string; position: Integer): Boolean;
begin
  result := string.Compare(hayStack, position-1, needle, 0, needle.Length) = 0;
end;

您可以使用CompareMem直接比较字符串内容:

  function IsSubStringAt(const aNeedle, aHaystack: String; aPosition: Integer): Boolean;
  var
    needleLen: Integer;
  begin
    needleLen := Length(aNeedle);
    result    := (needleLen + aPosition - 1) <= Length(aHaystack);

    if result then
      result := CompareMem(Pointer(aNeedle), @aHaystack[aPosition], needleLen * sizeof(Char));
  end;
请注意,如果草堆太短,无法在指定位置容纳针,则我们不需要进行任何比较

使用CompareMemAPI可以确保实现是可移植的,并且如果您曾经在Delphi的Unicode版本中迁移或使用此代码,只要考虑到字符类型的大小,也可以使用Unicode字符串类型,就像这里所做的那样


但是,这种方法假设字符串已经标准化到所需的任何程度,以便字符串的字节内容可以直接比较。

您可以使用CompareMem直接比较字符串内容:

  function IsSubStringAt(const aNeedle, aHaystack: String; aPosition: Integer): Boolean;
  var
    needleLen: Integer;
  begin
    needleLen := Length(aNeedle);
    result    := (needleLen + aPosition - 1) <= Length(aHaystack);

    if result then
      result := CompareMem(Pointer(aNeedle), @aHaystack[aPosition], needleLen * sizeof(Char));
  end;
请注意,如果草堆太短,无法在指定位置容纳针,则我们不需要进行任何比较

使用CompareMemAPI可以确保实现是可移植的,并且如果您曾经在Delphi的Unicode版本中迁移或使用此代码,只要考虑到字符类型的大小,也可以使用Unicode字符串类型,就像这里所做的那样


然而,这种方法假设字符串已经标准化到所需的任何程度,以便字符串的字节内容可以直接比较。

这里是一种非常快速的方法,用汇编语言编写。我通过修改原始Delphi的Pos功能实现了:

Function PosS (Substr:string; S:string; Position:integer) : integer;
  Asm
    TEST    EAX,EAX
    JE      @@NoWork

    TEST    EDX,EDX
    JE      @@StringEmpty

    PUSH    EBX
    PUSH    ESI
    PUSH    EDI

    MOV     ESI, EAX                         //  Pointer to Substr
    MOV     EDI, EDX                         //  Pointer to S
    MOV     EBX, ECX                         //  Position
    DEC     EBX

    MOV     ECX, [EDI-4]                     // Length (S)
    SUB     ECX, EBX

    PUSH    EDI
    ADD     EDI, EBX

    MOV     EDX, [ESI-4]                     // Length (Substr)

    DEC     EDX
    JS      @@Fail
    MOV     AL, [ESI]
    INC     ESI

    SUB     ECX, EDX                         // = Length (S) - Length (Substr) + 1
    JLE     @@Fail
@@Loop:
    REPNE   SCASB
    JNE     @@Fail
    MOV     EBX, ECX
    PUSH    ESI
    PUSH    EDI

    MOV     ECX, EDX
    REPE    CMPSB
    POP     EDI
    POP     ESI
    JE      @@Found
    MOV     ECX, EBX
    JMP     @@Loop

@@Fail:
    POP     EDX
    XOR     EAX, EAX
    JMP     @@Exit

@@StringEmpty:
    XOR     EAX, EAX
    JMP     @@NoWork

@@Found:
    POP     EDX
    MOV     EAX, EDI
    SUB     EAX, EDX
@@Exit:
    POP     EDI
    POP     ESI
    POP     EBX
@@NoWork:
  End;

这是一种非常快速的方法,用汇编语言编写。我通过修改原始Delphi的Pos功能实现了:

Function PosS (Substr:string; S:string; Position:integer) : integer;
  Asm
    TEST    EAX,EAX
    JE      @@NoWork

    TEST    EDX,EDX
    JE      @@StringEmpty

    PUSH    EBX
    PUSH    ESI
    PUSH    EDI

    MOV     ESI, EAX                         //  Pointer to Substr
    MOV     EDI, EDX                         //  Pointer to S
    MOV     EBX, ECX                         //  Position
    DEC     EBX

    MOV     ECX, [EDI-4]                     // Length (S)
    SUB     ECX, EBX

    PUSH    EDI
    ADD     EDI, EBX

    MOV     EDX, [ESI-4]                     // Length (Substr)

    DEC     EDX
    JS      @@Fail
    MOV     AL, [ESI]
    INC     ESI

    SUB     ECX, EDX                         // = Length (S) - Length (Substr) + 1
    JLE     @@Fail
@@Loop:
    REPNE   SCASB
    JNE     @@Fail
    MOV     EBX, ECX
    PUSH    ESI
    PUSH    EDI

    MOV     ECX, EDX
    REPE    CMPSB
    POP     EDI
    POP     ESI
    JE      @@Found
    MOV     ECX, EBX
    JMP     @@Loop

@@Fail:
    POP     EDX
    XOR     EAX, EAX
    JMP     @@Exit

@@StringEmpty:
    XOR     EAX, EAX
    JMP     @@NoWork

@@Found:
    POP     EDX
    MOV     EAX, EDI
    SUB     EAX, EDX
@@Exit:
    POP     EDI
    POP     ESI
    POP     EBX
@@NoWork:
  End;

@KenWhite Length是一种简单的内存读取。费用是堆分配。如果需要,可以很容易地将其移除。关于Pos,您必须了解的是,它搜索子字符串的第一次出现。如果子字符串不在那里,Pos必须在Pos 1、Pos 2、Pos 3处检查它,并一直检查到字符串的末尾。这意味着Pos的运行时间与草堆的长度成松散的比例。这是迈克尔想要避免的。这正是我想要避免的,大卫。你写得比我清楚。您的解决方案的一点是,在进行比较之前,副本会做很多工作,但是如果第一个字符不同,则代码无需再进一步,因为指针不在位置。@KenWhite Length是一个简单的内存读取。费用是堆分配。如果需要,可以很容易地将其移除。关于Pos,您必须了解的是,它搜索子字符串的第一次出现。如果子字符串不在那里,Pos必须在Pos 1、Pos 2、Pos 3处检查它,并一直检查到字符串的末尾。这意味着Pos的运行时间与草堆的长度成松散的比例。这是迈克尔想要避免的。这正是我想要避免的,大卫。你写得比我清楚。解决方案的一点是,在进行比较之前,副本会做很多工作,但如果第一个字符不同,则代码无需进一步操作,因为指针不在位置。如果指针在数据通过链接到达之前已知,你可以给自己做一个小型的状态机,它可以监听连续到达的针的字符。@Mar

泰恩针和其他99根不同长度的针是众所周知的。你会做100台不同的状态机,还是1台处理所有的100针?好吧,叫我奇肯先生,但我只想在没有一根针的情况下自己实施一个SM。OTOH,肯定有一些库代码可以实现多针速度优化。我是说,早期的一个我是指互联网前的站点间通信软件包可能有这样的串扰——在典型的调制解调器固件中发现这样的软件包并不奇怪,用于识别At命令等。顺便说一句,+1表示一个非常有趣的问题。@Chicken先生-我只是倾向于使用一个if-then-else列表,它不太漂亮,但它是有效的,可读性强:这就是我是一个小妞。我很确定Turbopower的ASync Pro有一些s-m组件。它们用于实现x-modem之类的协议。对于我的简单需求来说太复杂了:感谢+1。这是一个冗长的讨论吗?如果在数据通过链接到达之前就知道了指针,那么你可以把自己变成一个小状态机,它可以监听连续到达的指针的字符。@Martyn针头是已知的,还有其他99个不同长度的指针。你会做100台不同的状态机,还是1台处理所有的100针?好吧,叫我奇肯先生,但我只想在没有一根针的情况下自己实施一个SM。OTOH,肯定有一些库代码可以实现多针速度优化。我是说,早期的一个我是指互联网前的站点间通信软件包可能有这样的串扰——在典型的调制解调器固件中发现这样的软件包并不奇怪,用于识别At命令等。顺便说一句,+1表示一个非常有趣的问题。@Chicken先生-我只是倾向于使用一个if-then-else列表,它不太漂亮,但它是有效的,可读性强:这就是我是一个小妞。我很确定Turbopower的ASync Pro有一些s-m组件。它们用于实现x-modem之类的协议。对于我的简单需求来说太复杂了:谢谢你的+1。这是关于+1的冗长讨论吗?谢谢你。遗憾的是,我仍然使用Delphi6,因为我们的一些代码使用Kylix。当我看到一些新的编撰者拥有的一些语言特性时,我会流泪。例如,我很想使用未来的变量,我不知道你在抱怨代码中缺少哪些新的语言特性。当然不是用于字符串比较的伪对象方法,它只是一个好的老式函数的语法包装器,在不支持一流函数的OOb对象痴迷语言中,这种方法是必要的。您可以直接使用Windows CompareString API执行相同的操作,对于该API,String.Compare是一个简单的包装器,在使用过程中引入了使用基于0的索引而不是它所修饰的字符串类型的基于1的索引的混淆。谢谢Uwe。遗憾的是,我仍然使用Delphi6,因为我们的一些代码使用Kylix。当我看到一些新的编撰者拥有的一些语言特性时,我会流泪。例如,我很想使用未来的变量,我不知道你在抱怨代码中缺少哪些新的语言特性。当然不是用于字符串比较的伪对象方法,它只是一个好的老式函数的语法包装器,在不支持一流函数的OOb对象痴迷语言中,这种方法是必要的。您可以直接使用Windows CompareString API执行相同的操作,其中String.Compare是一个简单的包装器,它在过程中引入了使用基于0的索引而不是它所修饰的字符串类型的基于1的索引的混淆。这是我的答案中变体2的平台特定版本,也是Uwe的答案。这两个都是跨平台的。在windows上,它们是通过调用CompareString来实现的。非常正确——正如你所说,OP在评论中提到Kylix的可移植性是一个问题。通过使用CompareMem可以很容易地解决这一问题,CompareMem是可移植的,并且在假设字符串已经为比较目的进行了规范化的情况下是最有效的。这仍然避免了使用ANSI包装器例程,这不仅会带来一些开销,而且如果代码被移植到Unicode,可能会造成混乱,而且肯定会令人恼火。我已经相应地更新了答案,这使得它和其他答案之间有了更清晰的界限。我希望您能同意。这是我的答案中变体2的平台特定版本,也是Uwe的答案。这两个都是跨平台的。在windows上,它们是通过调用CompareString来实现的。非常正确——正如你所说,OP在评论中提到Kylix的可移植性是一个问题。通过使用CompareMem可以很容易地解决这一问题,CompareMem是可移植的,并且在假设字符串已经为比较目的进行了规范化的情况下是最有效的。这仍然避免了使用ANSI包装器例程,这不仅会带来一些开销,而且可能会造成混乱,而且肯定会让人恼火
他曾经将代码移植到Unicode。我已经相应地更新了答案,这使得它和其他答案之间有了更清晰的界限。我希望你能同意。那一定是一个相当古老的Pos功能。最新的是相当复杂和复杂的。谢谢你,adlabac,我来试试。那一定是一个相当古老的Pos功能。最新的是相当复杂和复杂的。谢谢你,阿德拉巴克,我来试一试。