最近使用lazarus BufDataset控件遇到中文字段名称过滤时出错的问题,曾尝试将中文字段名加双引号或中括号,但仍然不行。经跟踪Bufdataset源码发现procedure TCustomExpressionParser.ParseString里的procedure ReadWord没正确识别中文引起的,修正这个问题比较简单:
打开/fpcsrc/packages/fcl-db/src/dbase/dbf_prscore.pas
定位fpcsrc 3.2.2版本832、865和867行(fpcsrc3.3.1版本:837、870和872行),按以下添加#$80..#$FF,然后重新编译fpcsrc及应用程序就可以。
while (I2 <= Len) and (AnExpr[I2] in ['a'..'z', 'A'..'Z', '_', '0'..'9',#$80..#$FF]) do //第837行添加#$80..#$FF
// However string constants can also appear without delimiters 'a'..'z', 'A'..'Z', '_',#$80..#$FF://第870行添加#$80..#$FF begin while (I2 <= Len) and (AnExpr[I2] in ['a'..'z', 'A'..'Z', '_', '0'..'9',#$80..#$FF]) do //第872行添加#$80..#$FF Inc(I2); end;
过滤前:
修复前中文字段过滤出错:
修正后中文字段已能正确过滤:
按黄色行修改就可以。
procedure ReadWord(AnExpr: string); var OldI2: Integer; constChar: Char; begin isConstant := false; I1 := I2; while (I1 < Len) and (AnExpr[I1] = ' ') do Inc(I1); I2 := I1; if I1 <= Len then begin if AnExpr[I2] = HexChar then begin Inc(I2); OldI2 := I2; ReadConstant(AnExpr, true); if I2 = OldI2 then begin isConstant := false; while (I2 <= Len) and (AnExpr[I2] in ['a'..'z', 'A'..'Z', '_', '0'..'9',#$80..#$FF]) do Inc(I2); end; end else if AnExpr[I2] = FDecimalSeparator then ReadConstant(AnExpr, false) else // String constants can be delimited by ' or " // but need not be - see below // To use a delimiter inside the string, double it up to escape it case AnExpr[I2] of '''', '"': begin isConstant := true; constChar := AnExpr[I2]; Inc(I2); while (I2 <= Len) do begin // Regular character? if (AnExpr[I2] <> constChar) then Inc(I2) else // we do have a const, now check for escaped consts if (I2+1 <= Len) and (AnExpr[I2+1]=constChar) then Inc(I2,2) //skip past, deal with duplicates later else //at the trailing delimiter begin Inc(I2); //move past delimiter break; end; end; end; // However string constants can also appear without delimiters 'a'..'z', 'A'..'Z', '_',#$80..#$FF: begin while (I2 <= Len) and (AnExpr[I2] in ['a'..'z', 'A'..'Z', '_', '0'..'9',#$80..#$FF]) do Inc(I2); end; '>', '<': begin if (I2 <= Len) then Inc(I2); if AnExpr[I2] in ['=', '<', '>'] then Inc(I2); end; '=': begin if (I2 <= Len) then Inc(I2); if AnExpr[I2] in ['<', '>', '='] then Inc(I2); end; '&': begin if (I2 <= Len) then Inc(I2); if AnExpr[I2] in ['&'] then Inc(I2); end; '|': begin if (I2 <= Len) then Inc(I2); if AnExpr[I2] in ['|'] then Inc(I2); end; ':': begin if (I2 <= Len) then Inc(I2); if AnExpr[I2] = '=' then Inc(I2); end; '!': begin if (I2 <= Len) then Inc(I2); if AnExpr[I2] = '=' then //support for != Inc(I2); end; '+': begin Inc(I2); if (AnExpr[I2] = '+') and FWordsList.Search(PChar('++'), I) then Inc(I2); end; '-': begin Inc(I2); if (AnExpr[I2] = '-') and FWordsList.Search(PChar('--'), I) then Inc(I2); end; '^', '/', '\', '*', '(', ')', '%', '~', '$': Inc(I2); '0'..'9': ReadConstant(AnExpr, false); else begin Inc(I2); end; end; end; end;