2

I want to copy specific lines from a StringList, I want to copy all lines that have 'Domain Status:' into memo.lines.text I used the code below, but the problem is it copies only the first line, I want to copy all lines that have 'Domain Status:':

 const
 FieldNames: array[0..2] of string = ('Domain Status', 'domain status', 'Domain status');
 begin
  sl := TStringList.Create;
  try
    sl.Assign(Memo.Lines);
    for I := 0 to sl.Count-1 do begin
      sl[I] := TrimLeft(sl[I]);
    end;
    sl.NameValueSeparator := ':';
    for I := Low(FieldNames) to High(FieldNames) do begin
      status := Trim(sl.Values[FieldNames[I]]);
      if status <> '' then Break;
    end;
  finally
    sl.Free;
  end;
  memo1.lines.text:=status;

Example of text in the StringList :

Domain Name: yahoo.com
Registry Domain ID: 3643624_DOMAIN_COM-VRSN
Registrar WHOIS Server: whois.markmonitor.com
Registrar URL: http://www.markmonitor.com
Updated Date: 2022-03-09T15:51:45+0000
Creation Date: 1995-01-18T08:00:00+0000
Registrar Registration Expiration Date: 2023-01-19T05:00:00+0000
Registrar: MarkMonitor, Inc.
Registrar IANA ID: 292
Registrar Abuse Contact Email: email@markmonitor.com
Registrar Abuse Contact Phone: +1.2083895770
Domain Status: clientUpdateProhibited (https://www.icann.org/epp#clientUpdateProhibited)
Domain Status: clientTransferProhibited (https://www.icann.org/epp#clientTransferProhibited)
Domain Status: clientDeleteProhibited (https://www.icann.org/epp#clientDeleteProhibited)
Domain Status: serverUpdateProhibited (https://www.icann.org/epp#serverUpdateProhibited)
Domain Status: serverTransferProhibited (https://www.icann.org/epp#serverTransferProhibited)
Domain Status: serverDeleteProhibited (https://www.icann.org/epp#serverDeleteProhibited)
Registrant Organization: Yahoo Assets LLC
Registrant State/Province: VA

I would like to get :

clientUpdateProhibited
clientTransferProhibited
clientDeleteProhibited
serverUpdateProhibited
serverTransferProhibited
.....
without the http://www.icann.org...
Ken White
  • 123,280
  • 14
  • 225
  • 444
MrSiMo
  • 101
  • 7
  • Your code has a serious logic error. Your `if status <> '' then break;` is entirely wrong. It kicks you out of the loop after the first match is found, which explains why it only works one time. There are a few other issues in the code you've posted. I'd suggest that you use the debugger to step through the code, so you can see exactly what it's doing, and then try again. – Ken White Apr 04 '22 at 23:58

2 Answers2

4

You need to loop through the individual strings of the TStringList, the TStringList.Values[] property will not help you with this task, as it will only search for the 1st string with a matching name. You can, however, use the TStringList.Names[] and TStringList.ValueFromIndex[] properties to help you.

Also, you don't need the FieldNames[] array at all. Use a case-insensitive comparison, like SysUtils.SameText() instead.

Try something more like this:

sl := TStringList.Create;
try
  sl.Assign(Memo.Lines);
  sl.NameValueSeparator := ':';
  for I := 0 to sl.Count-1 do begin
    sl[I] := TrimLeft(sl[I]);
    if SameText(sl.Names[I], 'Domain Status') then begin
      status := Trim(sl.ValueFromIndex[I]);
      status := Copy(status, 1, Pos(' ', status)-1);
      Memo1.Lines.Add(status);
    end;
  end;
finally
  sl.Free;
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I have used the above function to extract domain status with this function to extract the expiry date : begin sl := TStringList.Create; try sl.Assign(Memo.Lines); for I := 0 to sl.Count-1 do begin sl[I] := TrimLeft(sl[I]); end; sl.NameValueSeparator := ':'; for I := Low(FieldNames) to High(FieldNames) do begin expiry := Trim(sl.Values[FieldNames[I]]); if expiry <> '' then Break; end; finally sl.Free; end; end; – MrSiMo Apr 05 '22 at 16:16
  • but I got the error : screenshot: https://ibb.co/qyzDz1y clientUpdateProhibited (https://www.icann.org/epp#clientUpdateProhibited) is not a valise date time how to avoid this error? – MrSiMo Apr 05 '22 at 16:19
  • @MrSiMo First off, you are using the same code you were originally using for extracting the domain status, which was wrong code to begin with. Using code similar to what I gave you in my answer, simply changing `'Domain Status'` for `'Registrar Registration Expiration Date'`, should get you what you want. But using `sl.Values[]` will also work too, since there is only 1 expiration field. – Remy Lebeau Apr 05 '22 at 16:31
  • @MrSiMo As for the error, you did not show how you are converting `expiry` to a date/time, but there is no way you can get `clientUpdateProhibited` from the code you have shown PROVIDED THAT `FieldNames` is NOT your original array (why would you be looking for an expiration date in the `domain status` fields?). – Remy Lebeau Apr 05 '22 at 16:31
  • I have 2 fields: expiry domain status each one is in a different field in the database but I don't know why I'm getting this error, yes im converting expiry to get french date format :`**s := expiry; fs := TFormatSettings.Create; fs.DateSeparator := '-'; fs.TimeSeparator := ':'; fs.shortdateformat := 'yyyy-mm-dd'; FS.ShortTimeFormat := 'hh:nn:ss'; dt := StrToDatetime(s, fs); ds.DateSeparator := '-'; ds.TimeSeparator := ':'; ds.ShortDateFormat := 'dd-mm-yyyy'; ds.longtimeFormat := 'hh:mm:ss';**` – MrSiMo Apr 05 '22 at 16:54
  • I have find where is the error I'm sorry FieldNames has status instead of expiry it is fixed thank you @Remy – MrSiMo Apr 05 '22 at 16:58
  • 1
    @MrSiMo Look very carefully at the date/time values in your example text. They are in [ISO 8601 format](https://en.wikipedia.org/wiki/ISO_8601), which functions like `StrToDateTime()` DO NOT support, even with `TFormatSettings`, mainly because of the `T` that separates the date and time portions. So, you will have to either 1) split out the date and time portions first, then use `StrToDate()` and `StrToTime()` separately, and add the results together; Or 2) use the RTL's [`DateUtils.ISO8601ToDate()`](https://docwiki.embarcadero.com/Libraries/en/System.DateUtils.ISO8601ToDate) function instead. – Remy Lebeau Apr 05 '22 at 17:47
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/243622/discussion-between-mrsimo-and-remy-lebeau). – MrSiMo Apr 05 '22 at 17:50
2

Another approach is to use regular expressions. A bit overkill but if you can keep the regular expression around instead of recreating it with each use performance can be comparable.

procedure TForm1.Button1Click(Sender: TObject);
Var
    RegExDomainStatus : TRegEx;
    Match : TMatch;
    Alltext : string;
begin
  RegExDomainStatus.Create('(?<=^domain status: )[A-z]+',[roIgnoreCase,roMultiline]);
  Alltext := Memo1.Lines.Text;
  Memo1.Lines.Clear;
  match :=  RegExDomainStatus.Match(AllText);
  while match.Success do
  begin
     memo1.Lines.add(match.Value);
     match := match.NextMatch;
  end;
end;
Brian
  • 6,717
  • 2
  • 23
  • 31