Como retirar marcas de sotaque hebraico

17

Preciso de um truque de codificação de caracteres para remover marcas de acento hebraicas.

Amostra Antes

בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ

Amostra após

בראשית ברא אלהים את השמים ואת הארץ

Descriptografado
fonte

Respostas:

26

O truque aqui é perceber que esses caracteres que você vê na pergunta com os "acentos" não são realmente os personagens (ou seja, "Esses não são osdróidescaracteres que você está procurando ";-)). Os" acentos "são vários tipos de notações indicando coisas como:

  • vogais (linhas e pontos que normalmente estão sob as letras):

    letra base "ה" = "h"; "הֶ" = "heh" e "הָ" = "hah"

  • pronúncia (pontos que geralmente estão dentro ou acima das letras):

    "בּ" = "b" vs "ב" = "v" ou "שׂ" = "s" vs "" "=" sh "

  • pontuação

  • cantilação (como deve ser cantada)

As letras hebraicas reais são o que é mostrado na versão simplificada (ou seja, o resultado final do que está sendo solicitado aqui). O que estamos chamando aqui de "acentos" são conhecidos como sinais diacríticos. O artigo da Wikipedia sobre diacríticos hebraicos tem muitas informações boas sobre essas marcas, incluindo a seguinte imagem e legenda:

Gênesis 1: 9 E Deus disse: "Colham as águas"
Gênesis 1: 9 E Deus disse: "Colham as águas". Letras em preto, apontando em vermelho, cantilação em azul

Passar desses caracteres base para o que a primeira linha (com as vogais, etc.) mostra é uma questão de adicionar um ou mais "acentos". O Unicode (UTF-16 no SQL Server, embora a interpretação padrão lide apenas com os pontos de código UCS-2 / Plano Multilíngue Básico (BMP)) permite que alguns caracteres sobreponham outro caractere não sobreposto quando adjacentes a eles. Eles são conhecidos como caracteres combinados .

Significado:

SELECT DATALENGTH(N'מַ֖'); -- character taken from original given text

Devoluções:

6

não 2como a maioria das pessoas esperaria ver um caractere único de dois bytes. Então, talvez tentemos descobrir qual personagem existe fazendo:

SELECT UNICODE(N'מַ֖');

que retorna:

1502

Obviamente, as funções UNICODEe ASCIIretornam apenas o INTvalor do primeiro caractere de qualquer sequência que eles receberem. Mas um valor de 1502 cobre apenas 2 bytes, o que deixa 4 bytes não contabilizados. Observando os valores binários / hexadecimais do mesmo "caractere" hebraico:

SELECT NCHAR(1502), CONVERT(BINARY(2), UNICODE(N'מַ֖')), CONVERT(VARBINARY(10), N'מַ֖');

Nós temos:

מ
0x05DE  0xDE05B7059605

Agora, 0x05DE é a representação hexadecimal de 1502 e o 1502 é apenas o " מ ". A próxima parte pode ser separada em três conjuntos de 2 bytes: DE05 B705 9605 . Agora, os valores da string Unicode são armazenados no Little Endian, o que significa que a ordem dos bytes é revertida. Se mudarmos cada um desses três conjuntos, obteremos:

05DE (o caractere base) 05B7 0596 (o não contabilizado por 4 bytes).

Está bem. Então, o que acontece se removermos esse caractere base?

SELECT REPLACE(N'מַ֖' COLLATE Hebrew_BIN2, NCHAR(1502) COLLATE Hebrew_BIN2, '');

Isso retorna os dois caracteres restantes (não é fácil ver aqui, então eu criei a seguinte linha como um cabeçalho para aumentar o tamanho da fonte; você também pode executar o acima REPLACEpara vê-los):

Remover o מ do מַ֖ deixa dois caracteres na parte inferior: ַ֖

Portanto, precisamos remover cada ponto de código individual que é um desses caracteres combinados "extras" (encontrados em: http://unicode-table.com/en/search/?q=hebrew ) e isso nos deixará com os caracteres base. Podemos fazer isso via:

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;

E então podemos testá-lo com o texto original da seguinte maneira:

DECLARE @Hebrew NVARCHAR(200) = N'בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ';

SELECT dbo.RemoveHebrewAccents(@Hebrew);

Devoluções:

בראשית ברא אלהים את השמים ואת הארץ


Notas Adicionais:

  • Tecnicamente, existe um conjunto de pontos de código entre 64298 e 64334 que possuem algumas vogais e "acentos" de pronúncia incorporados ao personagem. Se eles precisam ser manipulados, isso pode ser um segundo passo na função para fazer uma simples substituição desses caracteres.

  • Parece que esses pontos de código de sotaque, pontuação etc. etc correspondem apenas ao usar um agrupamento binário. Mesmo usando Hebrew_100_CS_AS_KS_WS_SCnão combinava com eles. Mas o seguinte fez trabalho: Hebrew_BIN, Hebrew_BIN2, Latin1_General_BIN, e Latin1_General_BIN2. Na função eu acabei usando Hebrew_BIN2. Observe que, ao usar agrupamentos binários, a menos que você tenha uma necessidade específica de usar os _BINagrupamentos mais antigos , você deve usar apenas os _BIN2agrupamentos mais recentes .

  • Para quem está curioso, o texto de amostra hebraico é na verdade Bereishis 1: 1 (que também é a primeira palavra do lado direito, pois o hebraico é lido da direita para a esquerda; em inglês seria "Gênesis 1: 1" isso não é uma tradução direta da palavra, apenas o nome do primeiro livro da Torá / Bíblia; a tradução direta é "no começo"):

    No começo de Deus criando os céus e a Terra

  • 19-0-2015: Encontrei ótimos recursos que explicam os caracteres combinados e o conjunto de caracteres hebraicos:

Solomon Rutzky
fonte
@ Kin Obrigado! (novamente :). Vamos ver quanto tempo o seu comentário sobrevive esta ;-D tempo (nota para o nosso fantasma limpeza "processo": que não era para ter qualquer rude ou sarcástico implicações, e este smiley com halo prova que 😇 como faz este gato de sorriso 😺)
Solomon Rutzky / 02/15
1
e novamente aprendo algo inesperado com suas respostas. Agradável!
Max Vernon
1
Uau! Uma boa resposta lingüística apresentada com uma excelente descrição da manipulação de codificação! Obrigado, Salomão!
Mike Williamson
1

Esse é um problema interessante, e eu já enfrentei um tempo atrás trabalhando com caracteres japoneses. Eu bati um pouco em uma parede de tijolos tentando localizar seus personagens problemáticos, embora eu espere que isso leve você a algum lugar para encontrá-los.

Primeiro, coloquei todos os NCHARs em uma tabela:

SET NOCOUNT ON  

DECLARE @cnt INT = 1
DECLARE @sqlcmd NVARCHAR(512) = ''

CREATE TABLE #CHARS (
[CharOrder] INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
[Result] NVARCHAR(4) 
)

WHILE @cnt < 65536
BEGIN

SELECT @sqlcmd = '
INSERT #CHARS
    ([Result] )
SELECT NCHAR(' + CAST(@cnt AS NVARCHAR) + ')
'

EXEC sys.sp_executesql @sqlcmd

SET @cnt +=1 
END

Então localizei um dos caracteres não acentuados:

SELECT  c.CharOrder, c.Result
FROM    #CHARS AS c
WHERE c.Result = N'ר'
ORDER BY c.CharOrder

Então localizei o intervalo de caracteres em que os caracteres hebraicos estão:

SELECT  c.CharOrder, c.Result
FROM    #CHARS AS c
WHERE c.CharOrder >= 1488
AND c.CharOrder < 1523
ORDER BY c.CharOrder

Mas, tentando encontrar os caracteres acentuados que você deseja, eles parecem não aparecer, exceto um hit no código 8501.

SELECT  c.CharOrder ,
        c.Result
FROM    #CHARS AS c
WHERE   c.Result IN ( N'רֵ', N'א', N'שִׁ֖', N'י', N'ת', N'בְּ', N'בָּ', N'רָ֣',
                      N'א', N'אֱ', N'לֹ', N'הִ֑', N'י', N'ם', N'אֵ֥', N'ת',
                      N'הַ', N'שָּׁ', N'מַ֖', N'יִ', N'ם', N'וְ', N'אֵ֥', N'ת',
                      N'הָ', N'אָֽ', N'רֶ', N'ץ' )
ORDER BY c.CharOrder

Então, apenas olhando os caracteres ao redor, não consigo identificar outras correspondências no seu texto.

SELECT  c.CharOrder, c.Result
FROM    #CHARS AS c
WHERE c.CharOrder >= 8499
AND c.CharOrder < 8539
ORDER BY c.CharOrder

Muitos deles parecem ser jogados como aqueles retângulos nebulosos do que quer que seja.

Mais uma vez, desculpe, não é uma solução, mas espero que ajude.

Erik Darling
fonte
1
re: "tentando encontrar os caracteres acentuados que você deseja, eles parecem não aparecer", é porque eles não existem ;-). Explico com mais detalhes na minha resposta, mas basicamente é um caractere base com um ou dois caracteres de sobreposição que ocupam a mesma posição visível que o caractere base.
Solomon Rutzky
3
Isso é muito legal. Eu nunca teria pensado que essas marcas eram separadas dos personagens. Obrigado.
Erik Darling
1

Eu usei uma tabela de números. Existem inúmeras postagens explicando o que é isso, por que é útil e como obtê-lo com eficiência.

Não uso nenhuma funcionalidade interna para converter caracteres acentuados em equivalentes não acentuados. Em vez disso, construo uma lista de pesquisa que você preencherá com as conversões necessárias. Você terá que usar nvarchare definir suas traduções como N'x', é claro.

Obrigado a este post pela dica de concatenação de linha.

drop table #Numbers;

select
    *
into #Numbers
from 
    (
    select *
    from (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11)) as T(N)
    ) as xx;

drop table #Lookups;

select
    *
into #Lookups
from 
    (
    select *
    from (values ('a','m'),('b','n'),('c','o'),('d','p'),('e','q'),('m','z')) as T(CharFrom,CharTo)
    ) as xx;


drop table #Inputs;

select
    *
into #Inputs
from 
    (
    select *
    from (values ('abcdefghi')
                ,('abtcd')
        ) as T(Word)
    ) as xx;


select
     ix.Word as Original
    ,(
    select
        Coalesce(l.CharTo, SUBSTRING(i.word, n.N, 1)) -- do not alias
    from #Inputs as i
    cross apply #Numbers as n
    left join #Lookups as l
        on l.CharFrom = SUBSTRING(i.word, n.N, 1)
    where n.N <= LEN(i.Word)
    and i.Word = ix.Word
    for xml path ('')
    ) as Substituted
from #Inputs as ix;
Michael Green
fonte
Michael, o hebraico não funciona dessa maneira. Estes não são "caracteres acentuados" verdadeiramente, da mesma forma que estes são: Ü ö ò ô å Ä Å É ï. Portanto, um método padrão de tradução / mapeamento não funcionará.
Solomon Rutzky
0

Aqui está o que funcionou se alguém no futuro quiser.

function accentHebrewToCleanHebrew($accentHebrew){ //Strip Extras $search = array("&#1425;", "&#1426;", "&#1427;", "&#1428;", "&#1429;", "&#1430;", "&#1431;", "&#1432;", "&#1433;", "&#1434;", "&#1435;", "&#1436;", "&#1437;", "&#1438;", "&#1439;", "&#1440;", "&#1441;", "&#1442;", "&#1443;", "&#1444;", "&#1445;", "&#1446;", "&#1447;", "&#1448;", "&#1449;", "&#1450;", "&#1451;", "&#1452;", "&#1453;", "&#1454;", "&#1455;", "&#1456;", "&#1457;", "&#1458;", "&#1459;", "&#1460;", "&#1461;", "&#1462;", "&#1463;", "&#1464;", "&#1465;", "&#1466;", "&#1467;", "&#1468;", "&#1469;", "&#1470;", "&#1471;", "&#1472;", "&#1473;", "&#1474;", "&#1475;", "&#1476;", "&#1477;", "&#1478;", "&#1479;"); $replace = ""; $cleanHebrew = str_replace($search, $replace, $accentHebrew); return $cleanHebrew; }

Descriptografado
fonte