Cómo quitar marcas de acento hebreo

17

Necesito un truco de codificación de caracteres para eliminar las marcas de acento hebreo.

Muestra antes

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

Muestra después

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

Descifrado
fuente

Respuestas:

26

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):

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

  • pronunciación (puntos que generalmente están dentro o encima de las letras):

    "בּ" = "b" vs "ב" = "v", o "שׂ" = "s" vs "שׁ" = "sh"

  • puntuación

  • Cantilación (cómo se debe cantar)

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"
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 2como 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 UNICODEy ASCIIsolo devuelven el INTvalor 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 REPLACEpara verlos):

Al eliminar מ de מַ֖, quedan dos caracteres en la parte inferior: ַ֖

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_SCno 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 _BINcolaciones más antiguas , solo debe usar las _BIN2colaciones 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:

Solomon Rutzky
fuente
@ Kin Gracias! (de nuevo :). Veamos cuánto tiempo su comentario sobrevive esta vez ;-D (tenga en cuenta nuestro "proceso" de limpieza de fantasmas: no se suponía que tuviera implicaciones groseras o sarcásticas, y este smiley con halo demuestra que 😇 al igual que este gato sonriente 😺)
Solomon Rutzky
1
y nuevamente aprendo algo inesperado de tus respuestas. ¡Agradable!
Max Vernon
1
¡Guauu! ¡Una buena respuesta lingüística incluida con una excelente descripción del manejo de la codificación! Gracias Solomon!
Mike Williamson
1

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.

Erik Darling
fuente
1
re: "tratando de encontrar los caracteres acentuados que desea, no parecen aparecer", eso es porque no existen ;-). Explico con más detalle en mi respuesta, pero básicamente es un carácter base con uno o dos caracteres superpuestos que ocupan la misma posición visible que el carácter base.
Solomon Rutzky
3
Eso es realmente genial. Nunca hubiera pensado que esas marcas estaban separadas de los personajes. Gracias.
Erik Darling
1

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 nvarchary 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;
Michael Green
fuente
Michael, el hebreo en realidad no funciona de esa manera. Estos no son "caracteres acentuados" realmente de la misma manera que estos son: Ü ö ò ô å Ä Å É ï. Por lo tanto, un método estándar de traducción / mapeo no funcionará.
Solomon Rutzky
0

Esto es lo que funcionó si alguien en el futuro quiere.

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; }

Descifrado
fuente