Preciso de um truque de codificação de caracteres para remover marcas de acento hebraicas.
Amostra Antes
בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ
Amostra após
בראשית ברא אלהים את השמים ואת הארץ
Preciso de um truque de codificação de caracteres para remover marcas de acento hebraicas.
Amostra Antes
בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ
Amostra após
בראשית ברא אלהים את השמים ואת הארץ
Respostas:
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):
pronúncia (pontos que geralmente estão dentro ou acima das letras):
pontuação
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". 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 2
como 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 UNICODE
e ASCII
retornam apenas o INT
valor 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 REPLACE
para vê-los):
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_SC
nã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 _BIN
agrupamentos mais antigos , você deve usar apenas os _BIN2
agrupamentos 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:
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.
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 nvarchar
e 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;
Ü ö ò ô å Ä Å É ï
. Portanto, um método padrão de tradução / mapeamento não funcionará.
Aqui está o que funcionou se alguém no futuro quiser.
function accentHebrewToCleanHebrew($accentHebrew){
//Strip Extras
$search = array("֑", "֒", "֓", "֔", "֕",
"֖", "֗", "֘", "֙", "֚", "֛", "֜",
"֝", "֞", "֟", "֠", "֡", "֢", "֣",
"֤", "֥", "֦", "֧", "֨", "֩", "֪",
"֫", "֬", "֭", "֮", "֯", "ְ", "ֱ",
"ֲ", "ֳ", "ִ", "ֵ", "ֶ", "ַ", "ָ",
"ֹ", "ֺ", "ֻ", "ּ", "ֽ", "־", "ֿ",
"׀", "ׁ", "ׂ", "׃", "ׄ", "ׅ", "׆", "ׇ");
$replace = "";
$cleanHebrew = str_replace($search, $replace, $accentHebrew);
return $cleanHebrew;
}