【问题标题】:Get First word that contains numbers获取第一个包含数字的单词
【发布时间】:2015-10-05 11:53:22
【问题描述】:

任何人都可以帮助我如何找到第一个包含数字的完整单词?我有一个地址,例如:

procedure TForm1.Button4Click(Sender: TObject);
var
  SourceString      : String;
  strArray  : TArray<string>;
  i         : Integer;
begin
  SourceString := 'Saint Steven St 6.A II.f 9';
  strArray     := SourceString.Split([' ']);

for i := 0 to Length(strArray)-1 do
  showmessage(strArray[i]);

结束;

结果:

Saint
Steven
St
6.A
II.f
9

我想得到第一个包含数字的单词。在示例中:“6.A”。

有人知道怎么做吗?

【问题讨论】:

  • 我很好奇如果是34th Street 会发生什么。为此,我会倒退。

标签: delphi delphi-xe7


【解决方案1】:

为避免将字符串拆分为单词:

function ExtractFirstWordWithNumber(const SourceString: String): String;
var
  i,start,stop: Integer;
begin
  for i := 1 to Length(SourceString) do
  begin
    if TCharacter.IsDigit(SourceString[i]) then
    begin // a digit is found, now get start location of word
      start := i;
      while (start > 1) and 
        (not TCharacter.IsWhiteSpace(SourceString[start-1])) do 
        Dec(start);
      // locate stop position of word
      stop := i;
      while (stop < Length(SourceString)) and 
        (not TCharacter.IsWhiteSpace(SourceString[stop+1])) do
        Inc(stop);
      // Finally extract the word with a number
      Exit(Copy(SourceString,start,stop-start+1));
    end;
  end;
  Result := '';
end;

首先定位一个数字,然后从数字位置提取单词。

【讨论】:

    【解决方案2】:

    通过循环字符串并检查每个字符来测试字符串是否包含数字。例如:

    function ContainsDigit(const S: string): Boolean;
    var 
      C: Char;
    begin
      for C in S do
        if (C >= '0') and (C <= '9') then
          exit(True);
      exit(False);
    end;
    

    或者您可能更喜欢使用 System.Character 单元中的记录辅助方法来编写 if 语句。

    uses
      System.Character;
    
    ....
    
    function ContainsDigit(const S: string): Boolean;
    var 
      C: Char;
    begin
      for C in S do
        if C.IsDigit then
          exit(True);
      exit(False);
    end;
    

    【讨论】:

    • 你也可以使用CharInSet(c, ['0'..'9'])函数。您可以使用它而不是 in 来避免您在其中一个 cmets 中提到的编译器警告。
    • @asd-tm 我个人并不热衷于CharInSet。我不相信它非常有效。
    【解决方案3】:

    您可以使用Regular Expressions 来完成此任务:

    const
      CWORDS = 'Saint Steven St 6.A II.f 9';
      CPATTERN = '([a-zA-z\.]*[0-9]+[a-zA-z\.]*)+';
    
    var
      re: TRegEx;
      match: TMatch;
    
    begin
      re := TRegEx.Create(CPATTERN);
      match := re.Match(CWORDS);
      while match.Success do begin
        WriteLn(match.Value);
        match := match.NextMatch;
      end;
    end.
    

    以上打印:

    6.A
    9


    要获得包含数字的第一个单词,如您的问题所要求的,您可以考虑在您的代码中添加一个函数:

    function GetWordContainingNumber(const AValue: string): string;
    const
      CPATTERN = . . .;//what the hell the pattern is
    var
      re: TRegEx;
      match: TMatch;
    begin
      re := TRegEx.Create(CPATTERN);
      match := re.Match(AValue);
      if match.Success then
        Result := match.Value
      else
        Result := '';
    end;
    

    新添加的函数可以这样调用:

    showmessage(GetWordContainingNumber(SourceString));
    

    【讨论】:

    • 这里的正则表达式是不是有点矫枉过正?
    • @David 我不这么认为。对我来说最奇怪的是拆分一个字符串然后为每个令牌调用一个过程,不是吗?
    • 好吧,除了您的代码与拆分不同。问问自己,如果“单词”包含[a-zA-Z\.] 以外的字符,它会做什么。我明白你关于避免调用 split 的观点,但你应该产生语义上等价的东西。
    • @David 我添加了\. 字符只是因为它是一个非单词字符。只有 OP 知道还有什么可以包含他的字符串。也许这样的解决方案应该更好:([^ 0-9]*[0-9]+[^ 0-9]*)+
    • 现在我同意并赞成,但我仍然不确定问题作者是否需要除 'a-z'、'A'..'Z' 之外的其他字母......可能他正在使用德语带有ßüöäö或西里尔字母等的字母表......
    【解决方案4】:

    您可以使用类似的方法来了解单词是否包含字符 '0'..'9'

      function DigitInWord(s: string): boolean;
      var
        ch: char;
      begin
        result := false;
        for ch :='0' to '9' do
          if Pos(s, ch) > 0 then
          begin
            result := true;
            break;
          end;
      end;
    

    【讨论】:

    • 使用IntToStr 是最重要的。也可以有一个从'0''9'char 循环变量。但是,正如您所写的那样,它很昂贵。您可能会遍历每个单词 10 次而不是一次。
    • 你说得对,@David 我已经用 char 循环变量编辑了帖子。
    【解决方案5】:
    function WordContainsNumber(const AWord: string): boolean;
    var
      i: integer;
    begin
      for i:=1 to Length(AWord) do
        if CharInSet(AWord[i], ['0'..'9']) then
          Exit(true);
    
      Exit(false);
    end;
    
    function GetFirstWordThatContainsANumber(const AWords: TArray<string>): string;
    var
      CurrentWord: string;
    begin
      Result := '';
    
      for CurrentWord in AWords do
        if WordContainsNumber(CurrentWord) then
          Exit(CurrentWord);        
    end;
    
    procedure TForm1.Button4Click(Sender: TObject);
    var
      SourceString      : String;
      strArray  : TArray<string>;
      i         : Integer;
    begin
      SourceString := 'Saint Steven St 6.A II.f 9';
      strArray     := SourceString.Split([' ']);
    
      for i := 0 to Length(strArray)-1 do
        showmessage(strArray[i]);
    
      ShowMessage('The first word containing a number is ' + GetFirstWordThatContainsANumber(strArray));    
    end;    
    

    【讨论】:

      猜你喜欢
      • 2013-09-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多