我有很多数据需要排序,其中一个字段包含车辆的品牌/型号以及注册表,有时用破折号 (-) 分隔,有时但事实并非如此。以下是此类字符串的示例:
VehicleModel - TU69YUP
VehicleModel - TU69 YUP
VehicleModel TU69YUP
VehicleModel TU69 YUP
还有一些其他的变化,但它们是我遇到的主要变化。有没有一种方法可以可靠地检查所有数据并将车辆注册与模型分开?
数据目前包含在 Paradox 数据库中,我可以顺利浏览该数据库。我没有数据库中包含的所有车型和名称的列表,同样,我也没有车牌列表。
该项目是用 Delphi/SQL 编写的,因此如果可能的话,我宁愿坚持使用其中之一。
最佳答案
前方有麻烦
如果该字段最初是由用户以您现在看到的形式输入的,那么我们可以假设没有进行验证,原始程序只会存储用户输入的任何内容。如果是这样的话,你就无法获得 100% 的准确性:人类总是会有意无意地犯错误。预计会出现此类人为错误:
- 缺少字段(即:仅注册,没有车辆信息 - 或反之亦然)
- 无意义的重复单词(例如:“Ford Ford K - TU 69 YUP”)
- 丢失字母、重复字母、多余的垃圾字母。示例:“对于 K - T69YUP”
- 字段顺序错误
- 其他你做梦也想不到的小错误。
- 连人类都无法理解的普通垃圾。
您可能已经猜到我在处理直接在文本字段中输入的数据时有点悲观。我在处理一个所有数据都是文本且没有验证的数据库时遇到了明显的不幸:您能猜出人们在允许自由用户输入的未经验证的日期字段中输入的那种废话吗?
计划
事情并不像看起来那么黑暗,你可能可以“修复”很多事情。这里的技巧是确保只修复明确的数据,并让人们筛选其余的内容。最简单的方法是执行以下操作:
- 查看您拥有的且尚未自动修复的数据。找出一条明确适用于大量记录的规则。
- 应用明确的规则。
- 重复此操作,直到只剩下几条记录。这些应该手动修复,因为它们抵制所有应用的自动方法。
实现
我强烈建议在所有测试中使用正则表达式,因为您最终肯定会实现许多不同的测试,并且正则表达式可以轻松“表达”搜索文本中的细微变化。例如,以下 reg-ex 可以解析所有 4 个示例并给出正确的结果:
(.*?)(\ {1,3}-\ {1,3})?(\b[A-Z]{2}\ {0,2}[0-9]{2}\ {0,3}[A-Z]{3}\b)
如果您以前从未使用过正则表达式,那么单个表达式看起来难以理解,但实际上非常简单。这不是一个 reg-ex 问题,所以我不会讨论任何细节。我宁愿解释一下我是如何想到这个想法的。
首先,如果文本包含车辆登记号码,这些号码将采用非常严格的格式:它们很容易匹配。根据您的示例,我假设所有注册号均采用以下形式:
LLNNLLL
其中“L”是字母,“N”是数字。我的正则表达式对它的解释是严格的:它需要正好两个大写字母,后跟少量空格(或没有空格),后跟正好两个数字,后跟少量空格(或没有空格),最后后面紧跟 3 个大写字母。正则表达式中处理该问题的部分是:
[A-Z]{2}\ {0,2}[0-9]{2}\ {0,3}[A-Z]{3}
正则表达式的其余部分确保注册号不会嵌入到其他单词中,处理将文本分组到捕获组中并为 VehicleModel 创建一个“惰性捕获组”。
如果我自己实现这个,我可能会编写一个“主”函数和一些更简单的“case”函数,每个函数处理用户输入的一种变化。示例:
// 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;
这里的想法是尝试创建多个简单的过程,每个过程都以明确的方式理解一种输入;并确保每个步骤不会返回误报!最后不要忘记,人类应该处理最后几种情况,所以不要寻求解决所有问题的解决方案。
关于sql - 检测子串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9341651/