هل هناك دالة عكسية لـ *SysUtils.Format* في دلفي
سؤال
هل قام أحد بكتابة روتين "UnFormat" لدلفي؟
ما أتخيله هو معكوس ل SysUtils.Format ويبدو شيء من هذا القبيل
UnFormat('رقم %n وآخر %n',[float1, float2]);
لذلك يمكنك فك سلسلة إلى سلسلة من المتغيرات باستخدام سلاسل التنسيق.
لقد ألقيت نظرة على روتين "التنسيق" في SysUtils، لكنني لم أستخدم التجميع مطلقًا، لذا فهو لا معنى له بالنسبة لي.
المحلول
وهذا ما يسمى scanf في لغة C، لقد قمت بعمل نموذج دلفي لهذا:
function ScanFormat(const Input, Format: string; Args: array of Pointer): Integer;
var
InputOffset: Integer;
FormatOffset: Integer;
InputChar: Char;
FormatChar: Char;
function _GetInputChar: Char;
begin
if InputOffset <= Length(Input) then
begin
Result := Input[InputOffset];
Inc(InputOffset);
end
else
Result := #0;
end;
function _PeekFormatChar: Char;
begin
if FormatOffset <= Length(Format) then
Result := Format[FormatOffset]
else
Result := #0;
end;
function _GetFormatChar: Char;
begin
Result := _PeekFormatChar;
if Result <> #0 then
Inc(FormatOffset);
end;
function _ScanInputString(const Arg: Pointer = nil): string;
var
EndChar: Char;
begin
Result := '';
EndChar := _PeekFormatChar;
InputChar := _GetInputChar;
while (InputChar > ' ')
and (InputChar <> EndChar) do
begin
Result := Result + InputChar;
InputChar := _GetInputChar;
end;
if InputChar <> #0 then
Dec(InputOffset);
if Assigned(Arg) then
PString(Arg)^ := Result;
end;
function _ScanInputInteger(const Arg: Pointer): Boolean;
var
Value: string;
begin
Value := _ScanInputString;
Result := TryStrToInt(Value, {out} PInteger(Arg)^);
end;
procedure _Raise;
begin
raise EConvertError.CreateFmt('Unknown ScanFormat character : "%s"!', [FormatChar]);
end;
begin
Result := 0;
InputOffset := 1;
FormatOffset := 1;
FormatChar := _GetFormatChar;
while FormatChar <> #0 do
begin
if FormatChar <> '%' then
begin
InputChar := _GetInputChar;
if (InputChar = #0)
or (FormatChar <> InputChar) then
Exit;
end
else
begin
FormatChar := _GetFormatChar;
case FormatChar of
'%':
if _GetInputChar <> '%' then
Exit;
's':
begin
_ScanInputString(Args[Result]);
Inc(Result);
end;
'd', 'u':
begin
if not _ScanInputInteger(Args[Result]) then
Exit;
Inc(Result);
end;
else
_Raise;
end;
end;
FormatChar := _GetFormatChar;
end;
end;
نصائح أخرى
أعلم أن هذا يميل إلى تخويف الناس، ولكن يمكنك كتابة دالة بسيطة للقيام بذلك باستخدام التعبيرات العادية
'a number (.*?) and another (.*?)
إذا كنت قلقًا بشأن تعبيرات reg، فقم بإلقاء نظرة على www.regexbuddy.com ولن تنظر إلى الوراء أبدًا.
أميل إلى الاهتمام بهذا باستخدام محلل بسيط.لدي وظيفتان، إحداهما تسمى NumStringParts والتي ترجع عدد "الأجزاء" في سلسلة ذات محدد محدد (في حالتك فوق المساحة) وتقوم GetStrPart بإرجاع الجزء المحدد من سلسلة ذات محدد محدد.تم استخدام كلا الإجراءين منذ أيام Turbo Pascal في العديد من المشاريع.
function NumStringParts(SourceStr,Delimiter:String):Integer;
var
offset : integer;
curnum : integer;
begin
curnum := 1;
offset := 1;
while (offset <> 0) do
begin
Offset := Pos(Delimiter,SourceStr);
if Offset <> 0 then
begin
Inc(CurNum);
Delete(SourceStr,1,(Offset-1)+Length(Delimiter));
end;
end;
result := CurNum;
end;
function GetStringPart(SourceStr,Delimiter:String;Num:Integer):string;
var
offset : integer;
CurNum : integer;
CurPart : String;
begin
CurNum := 1;
Offset := 1;
While (CurNum <= Num) and (Offset <> 0) do
begin
Offset := Pos(Delimiter,SourceStr);
if Offset <> 0 then
begin
CurPart := Copy(SourceStr,1,Offset-1);
Delete(SourceStr,1,(Offset-1)+Length(Delimiter));
Inc(CurNum)
end
else
CurPart := SourceStr;
end;
if CurNum >= Num then
Result := CurPart
else
Result := '';
end;
مثال للاستخدام:
var
st : string;
f1,f2 : double;
begin
st := 'a number 12.35 and another 13.415';
ShowMessage('Total String parts = '+IntToStr(NumStringParts(st,#32)));
f1 := StrToFloatDef(GetStringPart(st,#32,3),0.0);
f2 := StrToFloatDef(GetStringPart(st,#32,6),0.0);
ShowMessage('Float 1 = '+FloatToStr(F1)+' and Float 2 = '+FloatToStr(F2));
end;
تعمل هذه الإجراءات الروتينية بشكل رائع مع السلاسل البسيطة أو الصارمة المحددة بفواصل أيضًا.تعمل هذه الإجراءات بشكل رائع في دلفي 2009/2010.