检测子字符串

时间:2012-02-18 13:37:25

标签: sql string delphi filtering

我有很多数据需要排序,其中一个字段包含车辆的品牌/型号以及reg,有时用短划线( - )分隔,但有时却不是。以下是此类字符串的示例:

  

VehicleModel - TU69YUP

     

VehicleModel - TU69 YUP

     

VehicleModel TU69YUP

     

VehicleModel TU69 YUP

还有其他一些变化,但它们是我遇到的主要变化。有没有办法让我可以可靠地查看所有数据并将车辆注册表从模型中分离出来?

数据目前包含在一个Paradox数据库中,我没有遇到任何问题。我没有列出数据库中包含的所有车型和名称,同样,我也没有车牌清单。

该项目是用Delphi / SQL编写的,所以如果可能的话,我宁愿坚持使用其中任何一个。

3 个答案:

答案 0 :(得分:5)

提前麻烦

如果该字段最初是由用户以您现在看到的形式输入的,那么我们可以假设没有验证,原始程序将只存储用户输入的内容。如果是这样的话,你就无法获得100%的准确性:人类总是会有意或无意地犯错误。期待这种人为错误:

  • 缺少字段(即:仅注册,没有车辆信息 - 或者相反)
  • 无意义的重复词语(例如:"福特福特K-TU 69 YUP")
  • 缺少字母,重复的字母,额外的垃圾信件。示例:"对于K-T69YUP"
  • 错误的字段顺序
  • 您甚至无法想象的其他小错误。
  • 即使是人类也不会理解的普通垃圾。

您可能已经猜到,在将人类输入的数据直接处理到文本字段时,我有点悲观。我有一个明显的不幸来处理一个数据库,其中所有数据都是文本而且没有验证:你能猜出在无效的日期字段中输入允许免费用户输入的无意义人的类型吗?

计划

事情并不像他们看起来那么黑暗,你可能会修复"许多事。这里的诀窍是确保你只修复那些明确无误的数据,然后让人类筛选出其他东西。最简单的方法是做这样的事情:

  • 查看您拥有的数据,但尚未自动修复。找出明确适用于大量记录的规则。
  • 应用明确的规则。
  • 重复直到只剩下几条记录。这些应该手动修复,因为它们抵制了所有应用的自动方法。

实施

我强烈建议在所有测试中使用正则表达式,因为你肯定会最终实现许多不同的测试,正则表达式可以很容易地表达"搜索文本的细微变化。例如,以下注册表可以解析所有4个示例并给出正确的结果:

(.*?)(\ {1,3}-\ {1,3})?(\b[A-Z]{2}\ {0,2}[0-9]{2}\ {0,3}[A-Z]{3}\b)

如果您之前从未使用过正则表达式,那么单个表达式看起来难以理解,但事实上它非常简单。这不是一个注册问题,所以我没有详细说明。我想解释一下我是如何想出这个想法的。

首先,如果文本包含车辆登记号码,那么这些号码将采用非常严格的格式:它们易于匹配。根据您的示例,我假设所有注册号都是以下形式:

LLNNLLL

其中" L"是一封信," N"是一个数字。我的正则表达式对它的解释是严格的:它只需要两个大写字母,后面跟着少量空格(或没有空格),后面跟两个数字,后面跟着少量空格(或者没有)空格),最后是3个大写字母。处理该问题的正则表达式的一部分是:

[A-Z]{2}\ {0,2}[0-9]{2}\ {0,3}[A-Z]{3}

正则表达式的其余部分确保注册号码未被嵌入到其他单词中,处理将文本分组到捕获组中并创建一个"懒惰捕获组"对于VehicleModel。

如果我自己实施这个,我可能会写一个"主人"功能和一些更简单的案例"函数,每个函数处理用户输入的一种变化。例如:

// This function does a validation of the extracted data. For example it validates the
// Registration number, using other, more precise criteria. The parameters are VAR so the
// function may normalize the results.
function ResultsAreValid(var Make, Registration:string): Boolean;
begin
  Result := True; // Only you know what your data looks like and how it can be validated.
end;

// This is a case function that deals with a very rigid interpretation of user data
function VeryStrictInterpretation(const Text:string; out Make, Registration: string): Boolean;
var TestMake, TestReg: string;
    // regex engine ...
begin
  Result := False;
  if (your condition) then
    if ResultsAreValid(TestMake, TestReg) then
    begin
      Make := TestMake;
      Registration := TestReg;
      Result := True;
    end;    
end;

// Master function calling many different implementations that each deal with all sorts
// of variations of input. The most strict function should be first:
function MasterTest(const Text:string; out Make, Registration: string): Boolean;
begin
  Result := VeryStrictInterpretation(Text, Make, Registration);
  if not Result then Result := SomeOtherImplementation(Text, Make, Registration);      
  if not Result then Result := ThirdInterpretation(Text, Make, Registration);      
end;

这里的想法是尝试制作多个SIMPLE程序,每个程序都以明确的方式理解一种输入;并确保每个步骤都不会返回误报!最后不要忘记,一个人应该处理最后几个案例,所以不要瞄准一个解决方案。

答案 1 :(得分:0)

假设他们的格式相同。字[空间]字

然后你可以遍历所有这些,如果遇到没有破折号的空白,请插入破折号。然后正常分裂。

答案 2 :(得分:0)

这是一个代码示例。 它将检查-并删除许可证号中的可能空格。

注意:(由Ken White评论),如果车辆包含空格,则必须同时处理。

type
  EMySplitError = class(Exception);

procedure SplitVehicleAndLicense( s : String; var vehicle,license : String);
var
  p : Integer;
begin
  vehicle := '';
  license := '';
  p := Pos('-',s);
  if (p = 0) then
  begin // No split delimiter
    p := Pos(' ',s);
    if (p > 0) then
    begin
      vehicle := Trim(Copy(s,1,p-1));
      license := Trim(Copy(s,p+1,Length(s)));
    end
    else
      Raise EMySplitError.CreateFmt('Not a valid vehicle/license name:%s',[s]);
  end
  else
  begin
    vehicle := Trim(Copy( s,1,p-1));
    license := Trim(Copy( s,p+1,Length(s)));
  end;

  // Trim spaces in license
  repeat
    p := Pos(' ',license);
    if (p <> 0) then Delete(license,p,1);
  until (p = 0);
end;