我的任务是标准化一些地址信息。为了实现这个目标,我将地址字符串分解为细粒度值(我们的地址模式是,非常类似于谷歌的格式(。
迄今为止的进展:
我正在使用PHP,目前正在突破大厦,套房,房间号,等等…信息
一切都很顺利,直到我遇到地板
在大多数情况下,楼层信息表示为"floor 10">或"floor 86">。尼斯&简单
对于这一点,我可以简单地断开字符串上的字符串("room">、《floor》等(
问题:
但后来我在我的测试数据集中注意到了一些东西。在某些情况下,楼层的表示更像"2nd floor">
这让我意识到,我需要为FLOOR信息的整个变化做好准备
有一些选项,如"3rd Floor">、"22th Floor">和《1ST Floor》。那么,拼写出来的变体,比如"12th Floor">呢
成年男子这很快就会变得一团糟。
我的目标:
我希望有人知道一个库或已经解决了这个问题的东西
然而,在现实中,对于如何在如此多样化的标准上优雅地处理字符串分割问题(注意避免误报,如"3rd St">(,我会非常满意。
首先,您需要拥有所有可能的输入格式的详尽列表,并决定要深入到什么程度。如果您认为拼写出来的变体是无效的,您可以应用简单的正则表达式来捕获数字并检测令牌(房间、楼层…(
我将从阅读PHP中的regex开始。例如:
$floorarray = preg_split("/sfloors/i", $floorstring)
其他有用的功能是preg_grep
、preg_match
等
编辑:添加了一个更完整的解决方案。
此解决方案将描述楼层的字符串作为输入。它可以是各种格式,例如:
- 102层
- 102层
- 102层
- 102层
- 102层
- 102层
- 等等
在我看到一个示例输入文件之前,我只是从你的帖子中猜测这将是足够的。
<?php
$errorLog = 'error-log.txt'; // a file to catalog bad entries with bad floors
// These are a few example inputs
$addressArray = array('Fifty-second Floor', 'somefloor', '54th floor', '52qd floor',
'forty forty second floor', 'five nineteen hundredth floor', 'floor fifty-sixth second ninth');
foreach ($addressArray as $id => $address) {
$floor = parseFloor($id, $address);
if ( empty($floor) ) {
error_log('Entry '.$id.' is invalid: '.$address."n", 3, $errorLog);
} else {
echo 'Entry '.$id.' is on floor '.$floor."n";
}
}
function parseFloor($id, $address)
{
$floorString = implode(preg_split('/(^|s)floor($|s)/i', $address));
if ( preg_match('/(^|^s)(d+)(st|nd|rd|th)*($|s$)/i', $floorString, $matchArray) ) {
// floorString contained a valid numerical floor
$floor = $matchArray[2];
} elseif ( ($floor = word2num($floorString)) != FALSE ) { // note assignment op not comparison
// floorString contained a valid english ordinal for a floor
; // No need to do anything
} else {
// floorString did not contain a properly formed floor
$floor = FALSE;
}
return $floor;
}
function word2num( $inputString )
{
$cards = array('zero',
'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten',
'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen', 'twenty');
$cards[30] = 'thirty'; $cards[40] = 'forty'; $cards[50] = 'fifty'; $cards[60] = 'sixty';
$cards[70] = 'seventy'; $cards[80] = 'eighty'; $cards[90] = 'ninety'; $cards[100] = 'hundred';
$ords = array('zeroth',
'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth', 'tenth',
'eleventh', 'twelfth', 'thirteenth', 'fourteenth', 'fifteenth', 'sixteenth', 'seventeenth', 'eighteenth', 'nineteenth', 'twentieth');
$ords[30] = 'thirtieth'; $ords[40] = 'fortieth'; $ords[50] = 'fiftieth'; $ords[60] = 'sixtieth';
$ords[70] = 'seventieth'; $ords[80] = 'eightieth'; $ords[90] = 'ninetieth'; $ords[100] = 'hundredth';
// break the string at any whitespace, dash, comma, or the word 'and'
$words = preg_split( '/([s-,](?!ands)|sands)/i', $inputString );
$sum = 0;
foreach ($words as $word) {
$word = strtolower($word);
$value = array_search($word, $ords); // try the ordinal words
if (!$value) { $value = array_search($word, $cards); } // try the cardinal words
if (!$value) {
// if temp is still false, it's not a known number word, fail and exit
return FALSE;
}
if ($value == 100) { $sum *= 100; }
else { $sum += $value; }
}
return $sum;
}
?>
在一般情况下,将单词解析为数字并不容易。我能找到的讨论这个问题的最好的线索在这里。这远不如把数字转换成单词的反问题那么容易。我的解决方案只适用于数字<2000年,它自由地解释了格式不好的结构,而不是抛出错误。此外,它对拼写错误根本没有弹性。例如:
- 第四十四秒=82
- 百分之五=2400
- 第五十六秒第九=67
如果你有很多输入,而且大多数都是格式良好的,那么为拼写错误抛出错误并不是什么大不了的事,因为你可以手动更正问题条目的短列表。然而,根据应用程序的不同,默默地接受错误的输入可能是一个真正的问题。这只是在决定是否值得让转换代码更健壮时需要考虑的问题。