需要帮助如何使用preg_replace_callback

时间:2019-04-22 02:48:46

标签: php regex

我有此代码返回:

float(-70.869444444444)

使用var_dump可以看到它找到了所有坐标,但是只显示了一个。

如何修改以下代码以显示所有转换为度数格式的坐标并显示文本?

想要的结果应该是:

-70.869 -6.35测试-127.49更多测试第二行-127.35

代码

$str60 = 'W07052 W0623 test E12727 more test second line E12725';

preg_match_all('/([EWSN])([0-9]{3})([0-9]{2})/ms', $str60, $matches);
$result60 = DMS2Decimal($degrees = (int) $matches[2][0], $minutes = (int) $matches[3][0], $seconds = 10, $direction = strtolower($matches[1][0]));


function DMS2Decimal($degrees = 0, $minutes = 0, $seconds = 0, $direction = 'n')
{
//converts DMS coordinates to decimal
//returns false on bad inputs, decimal on success

//direction must be n, s, e or w, case-insensitive
$d = strtolower($direction);
$ok = array('n', 's', 'e', 'w');

//degrees must be integer between 0 and 180
if (!is_numeric($degrees) || $degrees < 0 || $degrees > 180) {
    $decimal = false;
    //var_dump($decimal);
}
//minutes must be integer or float between 0 and 59
elseif (!is_numeric($minutes) || $minutes < 0 || $minutes > 59) {
    $decimal = false;
    //var_dump($decimal);
}
//seconds must be integer or float between 0 and 59
elseif (!is_numeric($seconds) || $seconds < 0 || $seconds > 59) {
    $decimal = false;
} elseif (!in_array($d, $ok)) {
    $decimal = false;
    //var_dump($decimal);
} else {
    //inputs clean, calculate
    $decimal = $degrees + ($minutes / 60) + ($seconds / 3600);

    //reverse for south or west coordinates; north is assumed
    if ($d == 's' || $d == 'w') {
        $decimal *= -1;
    }
}

return $decimal;
}

var_dump($matches);
var_dump($result60);

2 个答案:

答案 0 :(得分:1)

是的,preg_replace_callback是您想要的。我假设您想捕捉“ W0623”,因此调整了您的正则表达式。

尽管输出的唯一变化是将其四舍五入到小数点后三位,但我也对函数进行了一些整理。其余的只是整理您的条件,如果您愿意,可以忽略。

function DMS2Decimal($degrees = 0, $minutes = 0, $seconds = 0, $direction = 'n')
{
    //converts DMS coordinates to decimal
    //returns false on bad inputs, decimal on success

    $d = strtolower($direction);
    if (
        //degrees must be integer between 0 and 180
        (is_numeric($degrees) && $degrees >= 0 && $degrees <= 180) &&
        //minutes must be integer or float between 0 and 59
        (is_numeric($minutes) && $minutes >= 0 && $minutes <= 59) &&
        //seconds must be integer or float between 0 and 59
        (is_numeric($seconds) && $seconds >= 0 && $seconds <= 59) &&
        //direction must be n, s, e or w, case-insensitive
        (in_array($d, ['n', 's', 'e', 'w']))
    ) {
        $decimal = $degrees + ($minutes / 60) + ($seconds / 3600);        
        //reverse for south or west coordinates; north is assumed
        if ($d == 's' || $d == 'w') {
            $decimal *= -1;
        }
        return round($decimal, 3);
    } else {
        return false;
    }
}

$str60 = 'W07052 W0623 test E12727 more test second line E12725';
$result60 = preg_replace_callback(
    "/([EWSN])([0-9]{3})([0-9]{1,2})/ms",
    function($m) {return DMS2Decimal((int)$m[2], (int)$m[3], 10, $m[1]);},
    $str60
);
echo $result60;

输出:

-70.869 -62.053 test 127.453 more test second line 127.419

答案 1 :(得分:-1)

以下脚本可能会返回您想要的结果。我不确定是否为函数指定了正确的输入值,它基于this,其中NWSE是方向,下一个{2}数字可能是{{1} },之后的Degree位数字可能是{2},其余数字可能是Minute,该数字可能是也可能不是浮点数。

Second

输出

$str60 = 'N404536 W73592.4 test E73592.4 more test second line S73592.4';
$split_strings = preg_split('/\s/s', $str60);
foreach ($split_strings as $value) {
    if (preg_match('/([EWSN][0-9\.]{4,})/ms', $value)) {
        $result60 .= DMS2Decimal(
            $degrees = (int) substr($value, 1, 2), // Not sure, this might return degrees - e.g., W{73}592.4
            $minutes = (int) substr($value, 3, 2), // Not sure, this might return minutes - e.g., W735{92}.4
            $seconds = substr($value, 5) != null ? (int) substr($value, 5) : 0, // Not sure, this checks if second is available or place zero - e.g., W7359{2.4}
            $direction = substr($value, 0, 1) // This is direction East West North South - e.g., {W}73592.4
        ) . " ";
    } else {
        $result60 .= $value . " ";
    }

}
var_dump($result60);

function DMS2Decimal($degrees = 0, $minutes = 0, $seconds = 0, $direction = 'n')
{
//converts DMS coordinates to decimal
    //returns false on bad inputs, decimal on success

//direction must be n, s, e or w, case-insensitive
    $d = strtolower($direction);
    $ok = array('n', 's', 'e', 'w');

//degrees must be integer between 0 and 180
    if (!is_numeric($degrees) || $degrees < 0 || $degrees > 180) {
        $decimal = false;
        //var_dump($decimal);
    }
//minutes must be integer or float between 0 and 59
    elseif (!is_numeric($minutes) || $minutes < 0 || $minutes > 59) {
        $decimal = false;
        //var_dump($decimal);
    }
//seconds must be integer or float between 0 and 59
    elseif (!is_numeric($seconds) || $seconds < 0 || $seconds > 59) {
        $decimal = false;
    } elseif (!in_array($d, $ok)) {
        $decimal = false;
        //var_dump($decimal);
    } else {
        //inputs clean, calculate
        $decimal = $degrees + ($minutes / 60) + ($seconds / 3600);

        //reverse for south or west coordinates; north is assumed
        if ($d == 's' || $d == 'w') {
            $decimal *= -1;
        }
    }

    return $decimal;
}