用 Lua 提取被 Unicode 空格和控制字符分割的单词

我需要一个纯 Lua (即没有使用外部 Unicode 库)的解决方案,用于提取字符串中某些 Unicode 控制字符和空格之间的单位。我想要作为分隔符使用的代码点如下:

0000-0020 007f-00a0 00ad 1680 2000-200a 2028-2029 202f 205f 3000

我知道如何访问字符串中的代码点,例如:

> for i,c in utf8.codes("é$ \tπ") do print(c) end
233
36
32
9
960
128515

但是我不确定如何“跳过”空格和制表符,并将其他代码点重组成字符串本身。在上面的示例中,我想删除 32 和 9,然后使用 utf8.char(233, 36) 和 utf8.char(960, 128515) 以某种方式获取 ["é$", "π"]。

似乎将所有内容放入数字表格中,并仔细遍历该表格以实现 for 循环和 if 语句是可行的,但是否有更好的方法?我尝试使用 string:gmatch,但那似乎要求我将我想要的每个区间都转换为 utf8 序列,而且不清楚该模式甚至看起来像什么。

是否有一种惯用的方法来提取空格之间的字符串?还是必须手动处理代码点表格? gmatch 看起来不适合这项任务。是这样吗?

点赞
用户1847592
用户1847592

需要耗费大量的工作来为每个范围的代码点生成UTF8编码。

是的,但当然不需要手动完成。

local function range(from, to)
   assert(utf8.codepoint(from) // 64 == utf8.codepoint(to) // 64)
   return from:sub(1,-2).."["..from:sub(-1).."-"..to:sub(-1).."]"
end

local function split_unicode(s)
   for w in s
      :gsub("[\0-\x1F\x7F]", " ")
      :gsub("\u{00a0}", " ")
      :gsub("\u{00ad}", " ")
      :gsub("\u{1680}", " ")
      :gsub(range("\u{2000}", "\u{200a}"), " ")
      :gsub(range("\u{2028}", "\u{2029}"), " ")
      :gsub("\u{202f}", " ")
      :gsub("\u{205f}", " ")
      :gsub("\u{3000}", " ")
      :gmatch"%S+"
   do
      print(w)
   end
end

测试:

split_unicode("@\0@\t@\x1F@\x7F@\u{00a0}@\u{00ad}@\u{1680}@\u{2000}@\u{2005}@\u{200a}@\u{2028}@\u{2029}@\u{202f}@\u{205f}@\u{3000}@")
2021-03-02 23:09:24