全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:2457
推到 Plurk!
推到 Facebook!

函數因式分解,如何分析字串

答題得分者是:jow
pceyes
尊榮會員


發表:70
回覆:657
積分:1140
註冊:2003-03-13

發送簡訊給我
#1 引用回覆 回覆 發表時間:2007-11-29 22:36:54 IP:220.141.xxx.xxx 訂閱
假如我有以下的函數執行正常:
{MARGEMDBFIELD,,<資料表名>,<搜尋欄位>,<搜尋值>,<取得欄位>} -> 傳回取得欄位的值
{MARGEFIELD<欄位>} -> 傳回某欄位的值
我想要將它們串起來使用如下:
{MARGEMDBFIELD,CL.MDB,DETAIL,個編,{MARGEFIELD鄰別},個編},姓名 }
它們的流程如下,有遞迴的行為,且須由內而外置換:
a. {MARGEFIELD鄰別} 取得 鄰別 例如: 09
b. {MARGEMDBFIELD,CL.MDB,LINCHIF,鄰別,09,個編}自LINCHIF資料表搜尋09鄰 取得 個編 例如 L123456789
c. {MARGEMDBFIELD,CL.MDB,DETAIL,個編,L123456789,姓名 } 自DETAIL資料表搜尋L123456789 取得 姓名欄位值 例如 林志玲
想很久了,不得其解,不知有沒有高人願意指點迷津, 先謝謝了!

------
努力會更接近成功
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#2 引用回覆 回覆 發表時間:2007-11-30 00:08:38 IP:123.193.xxx.xxx 訂閱
不知道這是不是你要的?
我將參數的位置調動了一下,
並將後面三個參數設置預設值(空字串)

[code delphi]
function MargeField(<取得欄位>: string;
<資料表名>: string='';
<搜尋欄位>: string='';
<搜尋鍵值>: string=''): string;
begin
Result := '';
if <資料表名> <> '' then
begin
//自CL.MDB中名為<資料表名>的Table中找尋<搜尋欄位>值==<搜尋值>的資料
//並將<取得欄位>的欄位值傳回.(Result = <取得欄位>的值)
end
else begin
//傳回欄位值,如你所述的 <鄰別>資料
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
TheName: string;
begin
TheName :=
MargeField('姓名','DETAIL' ,'個編',
MargeField('個編','LINCHIF','鄰別',
MargeField('鄰別')));
end;
[/code]


謹供參考
===================引 用 pceyes 文 章===================
假如我有以下的函數執行正常:
{MARGEMDBFIELD,,<資料表名>,<搜尋欄位>,<搜尋值>,<取得欄位>} -> 傳回取得欄位的值
{MARGEFIELD<欄位>} -> 傳回某欄位的值
我想要將它們串起來使用如下:
{MARGEMDBFIELD,CL.MDB,DETAIL,個編,{MARGEFIELD鄰別},個編},姓名 }
它們的流程如下,有遞迴的行為,且須由內而外置換:
a. {MARGEFIELD鄰別} 取得 鄰別 例如: 09
b. {MARGEMDBFIELD,CL.MDB,LINCHIF,鄰別,09,個編}自LINCHIF資料表搜尋09鄰 取得 個編 例如 L123456789
c. {MARGEMDBFIELD,CL.MDB,DETAIL,個編,L123456789,姓名 } 自DETAIL資料表搜尋L123456789 取得 姓名欄位值 例如 林志玲
想很久了,不得其解,不知有沒有高人願意指點迷津, 先謝謝了!
?
pceyes
尊榮會員


發表:70
回覆:657
積分:1140
註冊:2003-03-13

發送簡訊給我
#3 引用回覆 回覆 發表時間:2007-11-30 07:03:29 IP:220.141.xxx.xxx 訂閱
對不起, 表達不清,致您誤解, 以下是昨晚改的, 已可支援原先問題, 但第三層就不行了

[code delphi]
(* 取得另一個資料表鍵值欄位資料*)
// {margeMdbfield,,,,,}
function TForm1.GetMargeMDBField(MargeString:widestring):string;
var
split_st : Tstringlist;
mycn3,myRs3 : Variant;
myconnstr3, sqltext : string;
mdbfile,tablename,findfield,KeyValue,getfield:string;
icnt : integer;
begin
log_st.add('GetMargeMDBField: ' MargeString);
split_st := Tstringlist.create;
try
split_st.text := stringreplace(MargeString,',',#13,[rfReplaceAll]);
if split_st.count < 6 then exit; // 若不合法, 直接離開
(* 遞迴 自己呼叫自己*)
if split_st.count > 6 then begin
log_st.add('GetMargeMDBField split_st.count > 6');
(*先解決 可執行的部分*)
for icnt :=1 to split_st.count-1 do begin
if funcode(split_st[icnt])<>'' then
split_st[icnt]:= funcode(split_st[icnt]);
end;(*先解決 可執行的部分*)
// MARGEMDBFIELD
if pos('MARGEMDBFIELD',split_st[4])>0 then begin
split_st[4] := split_st[4] ','
split_st[5] ','
split_st[6] ','
split_st[7] ','
split_st[8] ','
split_st[9];
split_st[5] := split_st[10];
if Pos('{',split_st[4])>0 then
split_st[4]:=funcode(split_st[4]);
end;
end;(* 遞迴 自己呼叫自己*)
// 標準情形
mdbfile := split_st[1];
tablename := split_st[2];
findfield := split_st[3];
KeyValue := split_st[4]; //可以變動
log_st.add('GetMargeMDBField KeyValue: ' KeyValue);
getfield := split_st[5];
if Pos('{',keyvalue)>0 then
KeyValue := funcode(keyvalue);
(*執行資料庫搜尋*)
if fileexists(mdbfile) then begin
//建立Connection物件
myCn3:=CreateOleObject('ADODB.Connection');
myconnstr3:='Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' mdbfile;
myCn3.Open(myconnstr3);
//建立RecordSet物件
myRs3:=CreateOleObject('ADODB.RecordSet');
sqltext := 'select ' getfield ' from ' tablename ' where ' findfield '="' KeyValue '"';
log_st.add('GetMargeMDBField: ' sqltext);
myRs3.open(sqltext,myCn3,3,1);
if myrs3.recordcount>0 then begin
result := vartostr(myrs3.fields[getfield].value);
end
else begin
result := 'Not_Found';
end;
log_st.add('GetMargeMDBField Result: ' result);
myRs3.close;
mycn3.close;
myRs3 := null;
myCn3 := null;
end;(*執行資料庫搜尋*)
finally
split_st.free;
end;
end;(* 取得另一個資料表鍵值欄位資料*)
[/code]

新的問題如下:
{MARGEMDBFIELD,cl.mdb,master,戶號,{MARGEMDBFIELD,cl.mdb,detail,個編,{MARGEMDBFIELD,cl.mdb,linchef,鄰別,{MARGEMDBFIELD,cl.mdb,linchef,鄰別,{ MARGEFIELD 鄰別 },個編},個編},戶號},電話1}

------
努力會更接近成功
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#4 引用回覆 回覆 發表時間:2007-12-01 12:09:20 IP:123.193.xxx.xxx 訂閱
(1)你的程式碼中, 這裡會產生Memory leaks,
物件產生後, 沒有Free掉.

split_st := Tstringlist.create;
try
split_st.text := stringreplace(MargeString,',',#13,[rfReplaceAll]);
if split_st.count < 6 then exit; // 若不合法, 直接離開

(2)程式碼中, 沒有看到處理 {MARGEFIELD, 鄰別} 的動作?!

(3)新的問題描述有些怪怪的?鄰別 call 了兩次

新的問題如下:

{MARGEMDBFIELD,cl.mdb,master,戶號,
{MARGEMDBFIELD,cl.mdb,detail,個編,
{MARGEMDBFIELD,cl.mdb,linchef,鄰別,
{MARGEMDBFIELD,cl.mdb,linchef,鄰別, { MARGEFIELD 鄰別 },
個編},
個編},
戶號},
電話1}


以下提供個人的一些想法和程式流程, 供你參考...

[code delphi]
unit fMain;

interface

uses
Classes, Forms, StdCtrls, Mask, Controls;

type
TForm1 = class(TForm)
private
function Process(S: string): string;
function FunctionID(S: string): Integer;
function RemoveBraces(S: string): string;
function MARGEFIELD(P: TStringList): string;
function MARGEMDBFIELD(P: TStringList): string;
public
function Execute(S: string): string;
end;

var
Form1: TForm1;

implementation

uses SysUtils;

{$R *.dfm}

{ TForm1 }

function TForm1.Execute(S: string): string;
var
I: Integer;
Stack: TStringList;
begin
//(0)以TStringList來作為Stack,
//(1)先找到指令字串的起頭點 '{'
//(2)然後循序再找結尾點'}', 並送到 Process()去處理,
//(3)回傳值與Stack中pop出來的字串結合, 繼續(2)的動作
//(4)當Stack.Count = 0 時, 完成Execute()動作, 並傳回最後結果
Stack := TStringList.Create;
try
Result := '';
for I := 1 to Length(S) do
begin
if S[I] = '{' then
begin
Stack.Insert(0, Result);//PUSH
Result := S[I];
end
else begin
Result := Result S[I];
if S[I] = '}' then
begin
//完整指令字串
Result := Stack[0] Process(Result);
Stack.Delete(0);//POP
if Stack.Count = 0 then Break;
end;
end;
end;
finally
FreeAndNil(Stack);
end;
end;

function TForm1.RemoveBraces(S: string): string;
begin
S := Trim(S);
if S[1] = '{' then S := Copy(S,2,Length(S)-1);
if S[Length(S)] = '}' then S := Copy(S,1,Length(S)-1);
Result := S;
end;

function TForm1.FunctionID(S: string): Integer;
begin
Result := -1;
if S = 'MARGEFIELD' then Result := 0
else if S = 'MARGEMDBFIELD'then Result := 1;
end;

function TForm1.Process(S: string): string;
var
P: TStringList;//parameters
begin
Result := '';
P := TStringList.Create;
try
P.CommaText := RemoveBraces(S);
case FunctionID(P[0]) of
0: Result := MARGEFIELD(P);
1: Result := MARGEMDBFIELD(P);
end;
finally
FreeAndNil(P);
end;
end;

function TForm1.MARGEFIELD(P: TStringList): string;
begin
Result := '';
if (P.Count = 2) and (P[0] = 'MARGEFIELD') then
begin
//模擬取得鄰別欄位值, 實際情況可能是從資料庫取得吧?! ^_^
if P[1] = '鄰別' then Result := '09';
end;
end;

//{margeMdbfield,,,,,}
function TForm1.MARGEMDBFIELD(P: TStringList): string;
begin
Result := '';
if (P.Count = 6) and (P[0] = 'MARGEMDBFIELD') then
begin
//各傳入的參數值
// = P[1]
//
= P[2]
// = P[3]
// = P[4]
// = P[5]
//在這裡從資料庫的資料表
, 比對
//搜尋欄位的值, 若是等於, 則
//傳回欄位的值.
end;
end;

end.
[/code]
pceyes
尊榮會員


發表:70
回覆:657
積分:1140
註冊:2003-03-13

發送簡訊給我
#5 引用回覆 回覆 發表時間:2007-12-01 18:41:34 IP:122.127.xxx.xxx 訂閱
真不好意思, 誏您抓bug
您說得沒錯, memory 會出問題, 另外連問題也錯了
我只是要表現我的問題, 是要重複執行的行為

由於您的協助目前想的方法是先拆成以下陣列

{MARGEMDBFIELD,cl.mdb,master,戶號,X,電話1} 25234567
{MARGEMDBFIELD,cl.mdb,detail,個編,X,戶號} N1233211234567
{MARGEMDBFIELD,cl.mdb,linchef,鄰別,X,個編} L123459789
{ MARGEFIELD 鄰別 } 16

然後再代入先前的 X 內
再以反迴圈取得值,再代回 X
您的程式寫得很棒, 我會仔細閱讀, 再次謝謝您!
------
努力會更接近成功
編輯記錄
pceyes 重新編輯於 2008-12-22 16:38:52, 註解 無‧
pceyes
尊榮會員


發表:70
回覆:657
積分:1140
註冊:2003-03-13

發送簡訊給我
#6 引用回覆 回覆 發表時間:2007-12-02 23:21:29 IP:122.127.xxx.xxx 訂閱
程式改好了, 有始有終, 做個完整交代.

[code delphi]
// RPos(,,) -> position Value
// is 0 return latest Position Value
// If not found or Too Big Then Return -1
// So We Can Use RPos('{',Xstr,2)<>-1
// For Checking String Having Two Segement (Ex. {abc{1234}def}... )
function TForm1.Rpos(substr:widestring;str:widestring;num:integer):integer;
var
Num_st : Tstringlist;
Pnum : integer;
data_str ,head,tail: widestring;
begin
Num_st := Tstringlist.create;
try
data_str := str;
while pos(substr,data_str)>0 do begin
pnum := pos(substr,data_str);
Num_st.Add(inttostr(Pnum));
head := copy(data_str,1,pnum-1);
tail := copy(data_str,pnum 1,length(str)-length(head)-1);
data_str :=head '龘' tail;
end;
if num=0 then begin // RAT
result := strtoint(Num_st[Num_st.count-1]);
end
else begin // ? times Position
if (Num_st.Count > 0)and(num <= Num_st.Count) then begin
result := strtoint(Num_st[num-1]);
end
else begin // not found or Lower then Times
result :=-1;
end;
end;
finally
Num_st.free;
end;
end;

(*多重 funcode*)
// {MARGEMDBFIELD,CL.MDB,MASTER,戶號,{MARGEMDBFIELD,CL.MDB,DETAIL,個編,{MARGEMDBFIELD,CL.MDB,LINCHIEF,鄰別,{MARGEFIELD 鄰別},個編},戶號},電話1}
function Tform1.Mfuncode(str:widestring):string;
var
Xstr ,head,tail: widestring;
Splite_st : Tstringlist;
icnt : integer;
RepValue : string;
begin
log_st.add('Mfuncode: ' Str);
Splite_st := Tstringlist.create;
try
Xstr := trim(str);
while pos('{',Xstr)>0 do begin
Xstr := DelSegeMent(Xstr);(*刪除前後{}*)
// 取字串前段
head := copy(Xstr,1,pos('{',Xstr)-1);
delete(Xstr,1,pos('{',Xstr)-1);
// 取字串尾段
if rpos('}',xstr,2)<>-1 then begin
// 表示 兩層以上
// {MARGEMDBFIELD,cl.mdb,detail,個編,{MARGEMDBFIELD,cl.mdb,linchef,鄰別,{MARGEFIELD鄰別},個編},姓名}
tail := trim(copy(Xstr,rpos('}',Xstr,0) 1,length(str)-length(head)));
delete(Xstr,rpos('}',Xstr,0) 1,length(str)-length(head));
end
else begin
// 表示 兩層以內
// {MARGEMDBFIELD,cl.mdb,linchef,鄰別,{MARGEFIELD鄰別},中文鄰別}
tail := trim(copy(Xstr,rpos('}',Xstr,0) 1,length(str)-length(head)));
end;
if head <> '' then begin
Splite_st.add('{' head FinishCode tail '}');
end;
end;(*while*)
delete(Xstr,rpos('}',Xstr,0),length(str)-length(head));
Splite_st.add('{' Xstr '}');
(*反向置換值*)
// 先處理 {MARGEFIELD鄰別}
// 再處理 {MARGEMDBFIELD,cl.mdb,linchef,鄰別,,個編}
for icnt := splite_st.count-1 downto 0 do begin
// 有 才處理
if pos(FinishCode ,splite_st[icnt])>0 then begin
splite_st[icnt] := stringreplace(splite_st[icnt],FinishCode,RepValue,[rfReplaceAll]);
end;
RepValue := funCode(splite_st[icnt]);
end;(*for 反向置換值*)
result := RepValue;
finally
freeandnil(splite_st);
end;
end;(*多重 funcode*)

[/code]
------
努力會更接近成功
系統時間:2024-04-29 13:37:36
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!