Necesito un truco de codificación de caracteres para eliminar las marcas de acento hebreo.
Muestra antes
בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ
Muestra después
בראשית ברא אלהים את השמים ואת הארץ
Necesito un truco de codificación de caracteres para eliminar las marcas de acento hebreo.
Muestra antes
בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ
Muestra después
בראשית ברא אלהים את השמים ואת הארץ
Respuestas:
El truco aquí es darse cuenta de que estos personajes que ves en la pregunta con los "acentos" no son realmente los personajes (es decir, "Estos no son losdroideslos caracteres que busca ";-)). Los" acentos "son varios tipos de anotaciones que indican cosas como:
vocales (líneas y puntos que normalmente están debajo de las letras):
pronunciación (puntos que generalmente están dentro o encima de las letras):
puntuación
Las letras hebreas reales son lo que se muestra en la versión reducida (es decir, el resultado final de lo que se solicita aquí). A lo que nos referimos aquí como "acentos" se conoce como signos diacríticos. El artículo de Wikipedia sobre diacríticos hebreos tiene mucha buena información sobre estas marcas, incluida la siguiente imagen y leyenda:
Génesis 1: 9 Y Dios dijo: "Que se junten las aguas". Letras en negro, apuntando en rojo, cantillation en azul
Pasar de esos caracteres básicos a lo que muestra la primera línea (con las vocales, etc.) es una cuestión de agregar uno o más "acentos". Unicode (UTF-16 en SQL Server, aunque la interpretación predeterminada solo maneja los puntos de código UCS-2 / Plano multilingüe básico (BMP)) permite que algunos caracteres se superpongan a otro carácter no superpuesto cuando están adyacentes a ellos. Estos se conocen como caracteres combinados .
Sentido:
SELECT DATALENGTH(N'מַ֖'); -- character taken from original given text
Devoluciones:
6
no 2
como la mayoría de la gente esperaría al ver un solo carácter de doble byte. Entonces, tal vez tratemos de encontrar qué personaje está allí haciendo:
SELECT UNICODE(N'מַ֖');
que devuelve:
1502
Por supuesto, las funciones UNICODE
y ASCII
solo devuelven el INT
valor del primer carácter de cualquier cadena que se les dé. Pero un valor de 1502 solo cubre 2 bytes, lo que deja 4 bytes sin contabilizar. Mirando los valores binarios / hexadecimales de ese mismo "carácter" hebreo:
SELECT NCHAR(1502), CONVERT(BINARY(2), UNICODE(N'מַ֖')), CONVERT(VARBINARY(10), N'מַ֖');
obtenemos:
מ
0x05DE 0xDE05B7059605
Ahora, 0x05DE es la representación hexadecimal de 1502, y el 1502 es solo la " מ ". La siguiente parte se puede separar en tres conjuntos de 2 bytes: DE05 B705 9605 . Ahora, los valores de cadena Unicode se almacenan en Little Endian, lo que significa que se invierte el orden de los bytes. Si cambiamos cada uno de esos tres conjuntos obtenemos:
05DE (el carácter base) 05B7 0596 (el no contabilizado para 4 bytes).
Okay. Entonces, ¿qué sucede si eliminamos ese personaje base?
SELECT REPLACE(N'מַ֖' COLLATE Hebrew_BIN2, NCHAR(1502) COLLATE Hebrew_BIN2, '');
Eso devuelve los dos caracteres restantes (no es fácil de ver aquí, así que he hecho que la siguiente línea sea un encabezado para aumentar el tamaño de la fuente; también puede ejecutar lo anterior REPLACE
para verlos):
Por lo tanto, necesitamos eliminar cada punto de código individual que sea uno de estos caracteres combinados "adicionales" (que se encuentran en: http://unicode-table.com/en/search/?q=hebrew ) y eso nos dejará con los personajes base. Podemos hacerlo a través de:
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;
Y luego podemos probarlo con el texto original de la siguiente manera:
DECLARE @Hebrew NVARCHAR(200) = N'בְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ';
SELECT dbo.RemoveHebrewAccents(@Hebrew);
Devoluciones:
Notas adicionales:
Técnicamente, hay un conjunto de puntos de código entre 64298 y 64334 que tienen algunas vocales y "acentos" de pronunciación integrados en el carácter. Si es necesario manejarlos, puede ser un segundo paso en la función para hacer un reemplazo simple de esos caracteres.
Parece que estos puntos de código de acento, puntuación, etc. solo coinciden cuando se utiliza una intercalación binaria. Incluso el uso Hebrew_100_CS_AS_KS_WS_SC
no coincidió con ellos. Pero la siguiente hizo el trabajo: Hebrew_BIN
, Hebrew_BIN2
, Latin1_General_BIN
, y Latin1_General_BIN2
. En la función terminé usando Hebrew_BIN2
. Tenga en cuenta que cuando use colaciones binarias, a menos que tenga una necesidad específica de usar las _BIN
colaciones más antiguas , solo debe usar las _BIN2
colaciones más nuevas .
Para cualquiera que tenga curiosidad, el texto de muestra en hebreo es en realidad Bereishis 1: 1 (esa es también la primera palabra en el lado derecho ya que el hebreo se lee de derecha a izquierda; en inglés sería "Génesis 1: 1" esa no es una traducción directa de la palabra, solo el nombre del primer libro de la Torá / Biblia; la traducción directa es "al principio"):
En el comienzo de Dios creando los cielos y la tierra
2015-01-19: Encontré algunos recursos excelentes que explican la combinación de caracteres y el conjunto de caracteres hebreo:
Este es un problema interesante, y al que me enfrenté hace un tiempo trabajando con caracteres japoneses. Me golpeé un poco con una pared de ladrillos tratando de localizar a tus personajes problemáticos, aunque espero que esto te lleve a algún lugar para encontrarlos.
Primero puse todos los NCHAR en una tabla:
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
Luego localicé uno de los caracteres no acentuados:
SELECT c.CharOrder, c.Result
FROM #CHARS AS c
WHERE c.Result = N'ר'
ORDER BY c.CharOrder
Luego localicé el rango de caracteres en los que están los caracteres hebreos:
SELECT c.CharOrder, c.Result
FROM #CHARS AS c
WHERE c.CharOrder >= 1488
AND c.CharOrder < 1523
ORDER BY c.CharOrder
Pero tratando de encontrar los caracteres acentuados que desea, no parecen aparecer, excepto un hit en el 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
Entonces, solo mirando los caracteres circundantes, realmente no puedo identificar ninguna otra coincidencia con su texto.
SELECT c.CharOrder, c.Result
FROM #CHARS AS c
WHERE c.CharOrder >= 8499
AND c.CharOrder < 8539
ORDER BY c.CharOrder
Muchos de ellos parecen ser arrojados como esos pequeños rectángulos nebulosos de lo que sea.
Una vez más, lo siento, no es una solución, pero espero que ayude.
He usado una tabla de números. Hay varias publicaciones que explican qué es esto, por qué es útil y cómo obtener una de manera eficiente.
No utilizo ninguna funcionalidad incorporada para convertir caracteres acentuados al equivalente no acentuado. En cambio, construyo una lista de búsqueda que completará con las conversiones que necesita. Tendrás que usar nvarchar
y definir tus traducciones como N'x'
, por supuesto.
Gracias a esta publicación por el consejo de concatenación de filas.
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;
Ü ö ò ô å Ä Å É ï
. Por lo tanto, un método estándar de traducción / mapeo no funcionará.
Esto es lo que funcionó si alguien en el futuro quiere.
function accentHebrewToCleanHebrew($accentHebrew){
//Strip Extras
$search = array("֑", "֒", "֓", "֔", "֕",
"֖", "֗", "֘", "֙", "֚", "֛", "֜",
"֝", "֞", "֟", "֠", "֡", "֢", "֣",
"֤", "֥", "֦", "֧", "֨", "֩", "֪",
"֫", "֬", "֭", "֮", "֯", "ְ", "ֱ",
"ֲ", "ֳ", "ִ", "ֵ", "ֶ", "ַ", "ָ",
"ֹ", "ֺ", "ֻ", "ּ", "ֽ", "־", "ֿ",
"׀", "ׁ", "ׂ", "׃", "ׄ", "ׅ", "׆", "ׇ");
$replace = "";
$cleanHebrew = str_replace($search, $replace, $accentHebrew);
return $cleanHebrew;
}