求高效字串分析算法,提供思路也有分。(例:将'中山三路15号B座1501房',返回 '中山三路'和15) (200分)

  • 主题发起人 主题发起人 Pc 狂迷
  • 开始时间 开始时间
P

Pc 狂迷

Unregistered / Unconfirmed
GUEST, unregistred user!
如何返回'中山三路15号B座1501房'或如'中山三路西区15号B座1501房'这样的地址字串 的
路名( '中山三路')和 号数(15) 两值,希望前辈们指明一下高效处理的方法或思路。谢谢。
 
在设计结构时就应将路名和号数分别作为字段。
 
可数据是别人提供的,轮不到我说话呀!
 
select left(XX,charindex('路',XX)),substring(xx,charindex('路',XX)+1,charindex('号',XX)-charindex('路',XX)) from table
 
兄弟要搞机器智能呀?
 
正则表达式行不行?我不是很懂啊!
 
我的代码最终分解为下面的形式
中山三路西区
15,号
B,座
1501,房
function GetNextToken(S: String;
var iStart: Integer): String;
type
cs = Set of Char;
const
cs1: cs = ['0'..'9', 'a'..'z', 'A'..'Z'];
var
tp, tt: Boolean;
m: Integer;
begin
m := iStart;
tp := S[iStart] in cs1;
iStart := iStart + 1;
while iStart <= Length(S)do
begin
tt := S[iStart] in cs1;
if tt <> tp then
Break;
iStart := iStart + 1;
end;
Result := Copy(S, m, iStart - m);
end;

function SplitStr(S: String): String;
type
cs = Set of Char;
const
cs1: cs = ['0'..'9', 'a'..'z', 'A'..'Z'];
var
iv: Integer;
ls, lt: Boolean;
t: String;
begin
iv := 1;
ls := (Length(S) > 0) and (S[1] in cs1);
while iv <= Length(S)do
begin
lt := S[iv] in cs1;
t := GetNextToken(S, iv);
if Result <> '' then
begin
if not ls then
Result := Result + #13#10 + t
else
Result := Result + ',' + t;
end
else
Result := t;
ls := lt;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(SplitStr(Edit1.Text));
end;
 
SELECT LEFT(Col003, CHARINDEX('路', Col003)) AS Expr1, SUBSTRING(Col003,
CHARINDEX('路', Col003) + 1, CHARINDEX('号', Col003) - CHARINDEX('路', Col003))
AS Expr2
FROM A
WHERE (CHARINDEX('路', Col003) > 0) AND (CHARINDEX('号', Col003) > 0)
PC:
是这样的,你的数据里面有些没有路或号的所以会出错,
这样就把出错的记录去了,
呵呵
 
To LiChaoHui:
我只要 '中山三路' 和 15 就行了,谢谢。另外能否更高效一点呢?
 
没有什么高效的,晕~这个本来就很累赘的
 
那就更容易了,
查找路字和号字,然后取他们前面的东西就可以了
用增量字符串查找,
这儿有个函数
function FindStr(const S, S1: String;
var iStart: Integer;
IgnoreCase: Boolean): Integer;
var
SA, SB: String;
i, mat: Integer;
begin
Result := 0;
if iStart < 1 then
iStart := 1;
if not IgnoreCase then
begin
i := iStart;
mat := 1;
while i <= Length(S)do
begin
if S = S1[mat] then
begin
mat := mat + 1;
end
else
begin
i := i - mat + 1;
mat := 1;
end;
i := i + 1;
if mat > Length(S1) then
begin
iStart := i;
Result := i - mat + 1;
Break;
end;

end;
end
else
begin
SA := LowerCase(S1);
SB := UpperCase(S1);
i := iStart;
mat := 1;
while i <= Length(S)do
begin
if (S = SA[mat]) or (S = SB[mat]) then
begin
mat := mat + 1;
end
else
begin
i := i - mat + 1;
mat := 1;
end;
i := i + 1;
if mat > Length(S1) then
begin
iStart := i;
Result := i - mat + 1;
Break;
end;
end;
end;
iStart := i;
end;
 
To LiChaoHui:
感谢你的帮助,算法能否更高效一些呢? 谢谢。
 
如果是按“路”、“号”为关键字查找,然后取相关内容的话,LiChaoHui的算法也是可行
的。不过我估计用Pos函数可能更简单一些,效率也不一定很低(中等快),因为Pos函数在
汇编中用的是Scasb找首字符,用Cmpsb比较整个串。
不过我怀疑这种思路有问题。如果“中山三路”前面有字符你又如何分开?例如“广州市
东山区中山三路”还得按“区”、“市”等得过可靠的分隔点。所以最后你还得按
LiChaoHui说的第一种方法全部拆分,再根据拆分出来的片段来分析。
老天!这样效率高不了!
 
To Barton:
真正的地址远比这乱着呢! 如 广州市东山区中山三路翠园花园19栋C座1503,还
有村、街、巷、小区、大院 等等,想想就怕,所以我想得到一个快一点是算法。感觉上
用上了 POS 和 COPY 等几个函数后会很慢(因为处理量大,并有时间要求)。所以头痛。
 
哈哈。上次谁来着(也是广州的)和我讨论汇编。我测试了一下,QString算法最快,大约只
有Pos算法的1/2左右。我们用了四五个算法,pos不算快也不算慢。最快的就是它了。
 
补充一点点:
1.你只需要用查找而不用Copy。你可以在找到后用定长的PChar类型,既省时间又省空间。
在需要进一步处理的时候再变换成不定长的PChar(0终止串)。
2.QString也是汇编代码,我都没有搞懂。看看你能不能明白:
function Q_PosStr(const FindString, SourceString: string;
StartPos: Integer): Integer;
asm
PUSH ESI
PUSH EDI
PUSH EBX
PUSH EDX
TEST EAX,EAX
JE @@qt
TEST EDX,EDX
JE @@qt0
MOV ESI,EAX
MOV EDI,EDX
MOV EAX,[EAX-4]
MOV EDX,[EDX-4]
DEC EAX
SUB EDX,EAX
DEC ECX
SUB EDX,ECX
JNG @@qt0
XCHG EAX,EDX
ADD EDI,ECX
MOV ECX,EAX
JMP @@nx
@@fr: INC EDI
DEC ECX
JE @@qt0
@@nx: MOV EBX,EDX
MOV AL,BYTE PTR [ESI]
@@lp1: CMP AL,BYTE PTR [EDI]
JE @@uu
INC EDI
DEC ECX
JE @@qt0
CMP AL,BYTE PTR [EDI]
JE @@uu
INC EDI
DEC ECX
JE @@qt0
CMP AL,BYTE PTR [EDI]
JE @@uu
INC EDI
DEC ECX
JE @@qt0
CMP AL,BYTE PTR [EDI]
JE @@uu
INC EDI
DEC ECX
JNE @@lp1
@@qt0: XOR EAX,EAX
@@qt: POP ECX
POP EBX
POP EDI
POP ESI
RET
@@uu: TEST EDX,EDX
JE @@fd
@@lp2: MOV AL,BYTE PTR [ESI+EBX]
CMP AL,BYTE PTR [EDI+EBX]
JNE @@fr
DEC EBX
JE @@fd
MOV AL,BYTE PTR [ESI+EBX]
CMP AL,BYTE PTR [EDI+EBX]
JNE @@fr
DEC EBX
JE @@fd
MOV AL,BYTE PTR [ESI+EBX]
CMP AL,BYTE PTR [EDI+EBX]
JNE @@fr
DEC EBX
JE @@fd
MOV AL,BYTE PTR [ESI+EBX]
CMP AL,BYTE PTR [EDI+EBX]
JNE @@fr
DEC EBX
JNE @@lp2
@@fd: LEA EAX,[EDI+1]
SUB EAX,[ESP]
POP ECX
POP EBX
POP EDI
POP ESI
end;
 
function AnsiStrPos(Str, SubStr: PChar): PChar;
 
to barton:
function Q_PosStr 很好!在第二次 POS 时可以利用之前的结果。
 
是啊,有个StartPos参数。你可以定义一个结构,记录找到的串的起始位置、长度、属性
(是路、区、号还是别的什么),这样你不用Copy。
 
后退
顶部