String 高效地在字符串中搜索一组字符并返回第一个匹配项

String 高效地在字符串中搜索一组字符并返回第一个匹配项,string,performance,lua,match,String,Performance,Lua,Match,我正在将vt100(旧学校终端)实现到lua中,它在嵌入式MCU上运行。性能是这里的一个问题 给定的是一个字符串(输入行),其中包含多个(不可预测的数字)字符。 在这个字符串中,我想从一组字符中找到第一个匹配项 例如: -- ASCII value(hex) of keyboard keys. #define KEY_UP "\x41" #define KEY_DOWN "\x42" #define KEY_RIGHT "\x43" #define KEY_LEFT "

我正在将vt100(旧学校终端)实现到lua中,它在嵌入式MCU上运行。性能是这里的一个问题

给定的是一个字符串(输入行),其中包含多个(不可预测的数字)字符。 在这个字符串中,我想从一组字符中找到第一个匹配项

例如:

-- ASCII value(hex) of keyboard keys.
#define KEY_UP      "\x41"
#define KEY_DOWN    "\x42"
#define KEY_RIGHT   "\x43"
#define KEY_LEFT    "\x44"

-- terminal object is defined and created

function terminal:receive()
    -- Set buffer and shorthand to self.port.read
    local read = function() return self.port:read() end
    local received = ""

    while true do
        -- Read Input
        local line = read()
        if ( not line ) then break end
        received = received .. line

        -- Search for the key.
        -- Don't search in line, due different baudrates might not
        -- Get the entire digit at once.
        if ( received:find( KEY_UP ) ) then
            return KEY_UP
        elseif ( received:find( KEY_DOWN ) ) then
            return KEY_DOWN
        ... and so on
        end
    end
end

我的例子中的解决方案肯定有点慢。想出更高性能的解决方案并不难。但是最有效的解决方案是什么呢?

您可以制作一个包含所有要查找的字符的模式。然后,您可以捕获结果并返回它


如果您要查找的字符之间没有任何优先级顺序,则此操作有效。

由于所有匹配项都是一个字符长,您可以使用set
[]
来匹配和捕获
()
以查看匹配的内容

#define KEY_UP      "\x41"
#define KEY_DOWN    "\x42"
#define KEY_RIGHT   "\x43"
#define KEY_LEFT    "\x44"
-- assemble pattern once for performance
local KEY_pattern = "([" .. KEY_UP .. KEY_DOWN .. KEY_RIGHT .. KEY_LEFT .. "])"

-- ............... skipped ...............
local match_start, match_end, match_content = received:find(KEY_pattern)
if ( match_content )  then
    return match_content
end

你用过剖析器吗?您确定模式匹配部分是这里的性能瓶颈吗?可能不是,但这是另一个问题。我只是第一眼就关心匹配,因为我正在搜索大约40个键。如果匹配是第一个关键点之一,那么它肯定非常快,接收过程可能是瓶颈。但是,如果没有匹配项,那么就有40个:find()s,这需要几个刻度。为什么要先把字符串放在一起,然后再对其进行解析?为什么不在读取输入后立即检查键?@Sempie:如果将所有键放在一个模式中,则可以使用一个
:find()
,而不是40。。。