Comment supprimer les marques d'accent hébreu

17

J'ai besoin d'un tour d'encodage de caractères pour supprimer les marques d'accent hébreu.

Échantillon avant

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

Échantillon après

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

Déchiffré
la source

Réponses:

26

L'astuce ici est de réaliser que ces personnages que vous voyez dans la question avec les "accents" ne sont pas vraiment les personnages (c'est-à-dire "Ce ne sont pas lesdroïdescaractères que vous recherchez ";-)). Les" accents "sont différents types de notations indiquant des choses comme:

  • voyelles (lignes et points qui se trouvent généralement sous les lettres):

    lettre de base "ה" = "h"; "הֶ" = "heh" et "הָ" = "hah"

  • prononciation (points généralement à l'intérieur ou au-dessus des lettres):

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

  • ponctuation

  • cantillation (comment la chanter)

Les lettres hébraïques réelles sont ce qui est montré dans la version dépouillée (c'est-à-dire le résultat final de ce qui est demandé ici). Ce que nous appelons ici "accents" sont connus comme des signes diacritiques. L'article de Wikipédia sur les signes diacritiques hébreux contient de nombreuses bonnes informations sur ces marques, notamment l'image et la légende suivantes:

Gen. 1: 9 Et Dieu dit: "Que les eaux soient recueillies"
Gen. 1: 9 Et Dieu dit: "Que les eaux soient recueillies". Lettres en noir, pointant en rouge, cantillation en bleu

Passer de ces caractères de base à ce que montre la première ligne (avec les voyelles, etc.) consiste à ajouter un ou plusieurs "accents". Unicode (UTF-16 dans SQL Server, bien que l'interprétation par défaut ne gère que les points de code UCS-2 / Basic Multilingual Plane (BMP)) permet à certains caractères de superposer un autre caractère non superposé lorsqu'ils sont adjacents à eux. Ceux-ci sont connus sous le nom de combinaison de caractères .

Sens:

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

Retour:

6

pas 2comme la plupart des gens s'attendraient à voir un caractère à deux octets. Alors peut-être que nous essayons de trouver quel personnage est là en faisant:

SELECT UNICODE(N'מַ֖');

qui renvoie:

1502

Bien sûr, les fonctions UNICODEet ASCIIne renvoient que la INTvaleur du premier caractère de la chaîne qui leur est donnée. Mais une valeur de 1502 ne couvre que 2 octets, ce qui laisse 4 octets non comptabilisés. En regardant les valeurs binaires / hexadécimales de ce même "caractère" hébreu:

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

on a:

מ
0x05DE  0xDE05B7059605

Maintenant, 0x05DE est la représentation hexadécimale de 1502, et le 1502 n'est que le " מ ". La partie suivante peut être séparée en trois ensembles de 2 octets: DE05 B705 9605 . Maintenant, les valeurs de chaîne Unicode sont stockées dans Little Endian, ce qui signifie que l'ordre des octets est inversé. Si nous changeons chacun de ces trois ensembles, nous obtenons:

05DE (le caractère de base) 05B7 0596 (le non comptabilisé pour 4 octets).

D'accord. Alors, que se passe-t-il si nous supprimons ce caractère de base?

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

Cela renvoie les deux caractères restants (pas facile à voir ici, j'ai donc fait de la ligne suivante un en-tête afin d'augmenter la taille de la police; vous pouvez également exécuter ce qui précède REPLACEpour les voir):

La suppression du מ du מַ֖ laisse deux caractères en bas: ַ֖

Par conséquent, nous devons supprimer chaque point de code individuel qui est l'un de ces caractères de combinaison "supplémentaires" (disponible sur: http://unicode-table.com/en/search/?q=hebrew ) et cela nous laissera avec les caractères de base. Nous pouvons le faire 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;

Et puis nous pouvons le tester avec le texte original comme suit:

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

SELECT dbo.RemoveHebrewAccents(@Hebrew);

Retour:

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


Notes complémentaires:

  • Techniquement, il y a un ensemble de points de code entre 64298 et 64334 qui ont des voyelles et des "accents" de prononciation intégrés dans le caractère. Si ceux-ci doivent être traités, cela peut être une deuxième étape dans la fonction pour effectuer un simple remplacement de ces caractères.

  • Il semble que ces points de code d'accent, de ponctuation, etc. ne correspondent que lors de l'utilisation d'un classement binaire. Même l'utilisation Hebrew_100_CS_AS_KS_WS_SCne leur correspondait pas. Mais ce qui suit fait le travail: Hebrew_BIN, Hebrew_BIN2, Latin1_General_BINet Latin1_General_BIN2. Dans la fonction, j'ai fini par utiliser Hebrew_BIN2. Veuillez noter que lorsque vous utilisez des classements binaires, sauf si vous avez un besoin spécifique d'utiliser les _BINclassements plus anciens , vous ne devez utiliser que les _BIN2classements les plus récents .

  • Pour ceux qui sont curieux, l'exemple de texte hébreu est en fait Bereishis 1: 1 (c'est aussi le premier mot à droite car l'hébreu est lu de droite à gauche; en anglais, ce serait "Genèse 1: 1" cependant ce n'est pas une traduction directe du mot, juste le nom du premier livre de la Torah / Bible; la traduction directe est "au début"):

    Au début de la création de Dieu des cieux et de la Terre

  • 2015-01-19: J'ai trouvé d'excellentes ressources qui expliquent à la fois la combinaison de caractères et le jeu de caractères hébreux:

Solomon Rutzky
la source
@Kin Merci! (encore :). Voyons combien de temps votre commentaire survit cette fois ;-D (note à notre "processus" de nettoyage des fantômes: cela n'était pas censé avoir des implications grossières ou sournoises, et ce smiley avec halo prouve que - tout comme ce chat souriant 😺)
Solomon Rutzky
1
et encore une fois j'apprends quelque chose d'inattendu de vos réponses. Agréable!
Max Vernon
1
Hou la la! Une belle réponse linguistique avec une excellente description de la gestion de l'encodage! Merci, Salomon!
Mike Williamson
1

C'est un problème intéressant, et je l'ai rencontré il y a quelque temps en travaillant avec des caractères japonais. J'ai heurté un peu un mur de briques en essayant de localiser vos personnages problématiques, bien que j'espère que cela vous amènera quelque part à les trouver.

J'ai d'abord mis tous les NCHAR dans une table:

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

Ensuite, j'ai localisé l'un des caractères non accentués:

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

Ensuite, j'ai localisé la gamme de caractères dans lesquels se trouvent les caractères hébreux:

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

Mais en essayant de trouver les caractères accentués que vous voulez, ils ne semblent pas apparaître, sauf un hit au code 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

Donc, juste en regardant les personnages environnants, je ne peux pas vraiment identifier d'autres correspondances avec votre texte.

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

Beaucoup d'entre eux semblent être jetés comme ces petits rectangles nébuleux de quoi que ce soit.

Encore une fois, désolé, ce n'est pas une solution, mais j'espère que cela aide.

Erik Darling
la source
1
re: "essayer de trouver les caractères accentués que vous voulez, ils ne semblent pas apparaître", c'est parce qu'ils n'existent pas ;-). J'explique plus en détail dans ma réponse, mais en gros c'est un caractère de base avec un ou deux caractères de superposition qui prennent la même position visible que le caractère de base.
Solomon Rutzky
3
C'est vraiment cool. Je n'aurais jamais pensé que ces marques étaient distinctes des personnages. Merci.
Erik Darling
1

J'ai utilisé une table Numbers. Il existe un certain nombre de messages expliquant ce que c'est, pourquoi c'est utile et comment en obtenir un efficacement.

Je n'utilise aucune fonctionnalité intégrée pour convertir des caractères accentués en équivalent non accentué. Au lieu de cela, je construis une liste de recherche que vous remplirez avec les conversions dont vous avez besoin. Vous devrez bien sûr utiliser nvarcharet définir vos traductions N'x'.

Merci à ce post pour le conseil de concaténation de ligne.

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
la source
Michael, l'hébreu ne fonctionne pas vraiment de cette façon. Ce ne sont pas « caractères accentués » vraiment de la même manière que ceux - ci sont: Ü ö ò ô å Ä Å É ï. Par conséquent, une méthode de traduction / mappage standard ne fonctionnera pas.
Solomon Rutzky
0

Voici ce qui a fonctionné si quelqu'un à l'avenir le souhaite.

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

Déchiffré
la source