1

我正在尝试制作自定义搜索查询解析器。这个想法是用户可以编写特定的关键字以按例如艺术家、颜色和风格进行搜索。例如,如果用户搜索:

style:Emboss some keywords color:#333333 artist:"Tom Hank" steel

后端返回的结果是:

array(
    "style"  => "Emboss",
    0        => "some",
    1        => "keywords"
    "color"  => "#333333",
    "artist" => "Tom Hank", // Note the word is not broken
    2        => "steel"
)

到目前为止,我已经设法做到了 - 通过从一个没有问题的数组构建一个查询字符串。但是,我在将字符串解析为数组时遇到了问题——主要是因为有引号。

我到目前为止是

public function parseQuery($str) {
    $arr = array();

    $pairs = str_getcsv($str, ' '); // This bugs me

    foreach($pairs as $k => $v) {
        list($name, $value) = explode(":", $v, 2);

        if(!isset($value)) {
            $arr[] = $name;
        } else {
            $arr[$name] = $value;
        }
    }

    return $arr;
}

问题在于str_getcsv如果第一个引号之间或最后一个引号之后没有空格,该函数会中断引用的单词。它像这样分解它

Array
(
    [0] => Some
    [1] => string
    [2] => with
    [3] => but:"some <--- This is the sinner
    [4] => string"
)

如果but:和之间有空格,它可以工作"some string",但是我不希望这样。

我的问题是如何通过少用或不使用正则表达式来解决这个问题。

4

1 回答 1

3

试试这个......它是快速而肮脏的程序代码,但可以满足您的需求。您将对其进行重构以使其可维护。

<?php
$str = 'style:Emboss some keywords color:#333333 artist:"Tom Hank" steel';

$pos = 0;
$buffer = '';
$len = strlen($str);
$quote = false;
$key = '';
$arr = array();

while ($pos < $len) {
    switch ($str[$pos]) {
        case '"':
            $quote = !$quote;
            break;
        case ':':
            $key = $buffer;
            $buffer = '';
            break;
        case ' ':
            if ($quote) {
                $buffer .= $str[$pos];
            }
            elseif (!empty($key)) {
                $arr[$key] = $buffer;
                $key = '';
                $buffer = '';
            }
            else {
                $arr[] = $buffer;
                $buffer = '';
            }
            break;
        default:
            $buffer .= $str[$pos];
    }
    $pos++;
}
if (!empty($key)) {
    $arr[$key] = $buffer;
}
else {
    $arr[] = $buffer;
}

print_r($arr);
于 2013-06-27T00:26:45.200 回答