如何去除希伯来语重音标记

Dec*_*ted 17 sql-server collation encoding unicode

我需要一个字符编码技巧来去除希伯来语重音标记。

之前的样品

???????????? ??????? ????????? ??????????????? ???????????????

样品后

?????????????? ?? ????? ??????

Sol*_*zky 26

这里的诀窍是意识到你在问题中看到的带有“口音”的这些字符并不是真正字符字符(即“这些不是机器人您正在寻找的字符” ;-) )。“口音”是各种类型的符号,表示以下内容:

  • 元音(通常在字母下方的线和点):

    基本字母“?” = "h"; “??” = "呵呵" 和 "??" =“哈”

  • 发音(通常在字母内部或上方的点):

    “??” =“b”与“?” = "v", 或 "??" = "s" vs "??" =“嘘”

  • 标点

  • 颂歌(应该如何唱)

实际的希伯来字母是在精简版本中显示的(即此处请求的最终结果)。我们在这里所说的“口音”被称为变音符号。维基百科关于希伯来语变音符号的文章有很多关于这些标记的很好的信息,包括以下图像和标题:

创世记 1:9 上帝说:“要积水”
创世记 1:9 上帝说:“要积水。” 黑色的字母,红色的指向,蓝色的cantilation

从这些基本字符到第一行(带有元音等)显示的内容是添加一个或多个“重音”的问题。Unicode(SQL Server 中的 UTF-16,尽管默认解释仅处理 UCS-2/基本多语言平面 (BMP) 代码点)允许某些字符在与它们相邻时覆盖另一个非覆盖字符。这些被称为组合字符

意义:

SELECT DATALENGTH(N'???'); -- character taken from original given text
Run Code Online (Sandbox Code Playgroud)

返回:

6
Run Code Online (Sandbox Code Playgroud)

不像2大多数人所期望的那样看到单个双字节字符。因此,也许我们尝试通过执行以下操作来找出存在的字符:

SELECT UNICODE(N'???');
Run Code Online (Sandbox Code Playgroud)

返回:

1502
Run Code Online (Sandbox Code Playgroud)

当然,UNICODEandASCII函数只返回INT给定字符串的第一个字符的值。但是 1502 的值仅覆盖 2 个字节,这导致 4 个字节未计入。查看同一个希伯来语“字符”的二进制/十六进制值:

SELECT NCHAR(1502), CONVERT(BINARY(2), UNICODE(N'???')), CONVERT(VARBINARY(10), N'???');
Run Code Online (Sandbox Code Playgroud)

我们得到:

?
0x05DE  0xDE05B7059605
Run Code Online (Sandbox Code Playgroud)

现在,0x05DE是 1502 的十六进制表示,而 1502 只是“ ”。下一部分可以分成三个 2 字节的集合:DE05 B705 9605。现在,Unicode 字符串值存储在 Little Endian 中,这意味着字节顺序颠倒了。如果我们切换这三组中的每一个,我们会得到:

05DE(基本字符)05B7 0596(4个字节的下落不明)。

好的。那么如果我们删除那个基本字符会发生什么?

SELECT REPLACE(N'???' COLLATE Hebrew_BIN2, NCHAR(1502) COLLATE Hebrew_BIN2, '');
Run Code Online (Sandbox Code Playgroud)

这将返回剩余的两个字符(在这里不容易看到,所以我将以下行作为标题以增加字体大小;您也可以运行上面的代码REPLACE来查看它们):

删除 ? 来自 ???在底部留下两个字符:??

因此,我们需要去掉作为这些“额外”组合字符之一的每个单独的代码点(可在:http : //unicode-table.com/en/search/?q=hebrew 找到),这将使我们离开与基本字符。我们可以通过以下方式做到这一点:

CREATE FUNCTION dbo.RemoveHebrewAccents (@txeTwerbeH NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
WITH SCHEMABINDING
AS
BEGIN

  WITH base (dummy) AS
  (
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
  ), nums AS
  (
    -- we will want to generate code points 1425 - 1479
    SELECT TOP (55) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS [Num]
    FROM   base b1
    CROSS JOIN base b2
  )
  SELECT @txeTwerbeH = REPLACE(
                               @txeTwerbeH COLLATE Hebrew_BIN2,
                               NCHAR(1424 + nums.[Num]) COLLATE Hebrew_BIN2,
                               ''
                              )
  FROM   nums;

  RETURN @txeTwerbeH;
END;
Run Code Online (Sandbox Code Playgroud)

然后我们可以用原始文本进行测试,如下所示:

DECLARE @Hebrew NVARCHAR(200) = N'???????????? ??????? ????????? ???? ???????????? ?????? ????????';

SELECT dbo.RemoveHebrewAccents(@Hebrew);
Run Code Online (Sandbox Code Playgroud)

返回:

?????????????? ?? ????? ??????


补充说明:

  • 从技术上讲,在 64298 和 64334 之间有一组代码点,它们确实在字符中内置了一些元音和发音“口音”。如果需要处理这些字符,则可以在函数的第二步中对这些字符进行简单的替换。

  • 似乎这些重音、标点符号等代码点仅在使用二进制排序规则时才匹配。即使使用Hebrew_100_CS_AS_KS_WS_SC与它们不匹配。但下面做工作:Hebrew_BINHebrew_BIN2Latin1_General_BIN,和Latin1_General_BIN2。在我最终使用的函数中Hebrew_BIN2。请注意,在使用二进制排序规则时,除非您特别需要使用旧的排序规则,否则_BIN您应该只使用较新的_BIN2排序规则。

  • 对于任何好奇的人来说,希伯来语示例文本实际上是 Bereishis 1:1(这也是右侧的第一个单词,因为希伯来语是从右到左阅读的;但在英语中应该是“Genesis 1:1”那不是这个词的直接翻译,只是妥拉/圣经第一本书的名字;直接翻译是“在开头”):

    在神创造天地之初

  • 2015-01-19:我找到了一些很好的资源来解释组合字符和希伯来字符集: