Jak usunąć hebrajskie znaki akcentujące

17

Potrzebuję sztuczki kodowania Char, aby usunąć hebrajskie znaki akcentujące.

Próbka przed

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

Próbka po

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

Odszyfrowano
źródło

Odpowiedzi:

26

Sztuką jest, aby zdać sobie sprawę, że te znaki, które widzisz na pytanie z „akcentów” tak naprawdę nie są to znaki (czyli „To nie sądroidyznaki, których szukasz „;-)).„ Akcenty ”to różnego rodzaju notacje wskazujące na:

  • samogłoski (linie i kropki, które zwykle znajdują się pod literami):

    litera podstawowa „ה” = „h”; „הֶ” = „heh” i „הָ” = „hah”

  • wymowa (kropki, które są zwykle wewnątrz lub powyżej liter):

    „בּ” = „b” vs „ב” = „v” lub „שׂ” = „s” vs „שׁ” = „sh”

  • interpunkcja

  • cantillation (jak należy śpiewać)

Rzeczywiste litery hebrajskie są pokazane w wersji uproszczonej (tj. Końcowy wynik tego, o co tutaj proszono). To, co nazywamy tutaj „akcentem”, znane jest jako znaki diakrytyczne. Artykuł w Wikipedii na temat hebrajskich znaków diakrytycznych zawiera wiele dobrych informacji na temat tych znaków, w tym następujący obraz i podpis:

Rdz 1: 9 I Bóg powiedział: „Niech gromadzą się wody”
Rdz 1: 9 I Bóg powiedział: „Niech gromadzą się wody”. Litery czarne, wskazujące na czerwono, cantillation na niebiesko

Przejście od tych podstawowych znaków do tego, co pokazuje pierwsza linia (z samogłosek, itp.), Polega na dodaniu jednego lub więcej „akcentów”. Unicode (UTF-16 w SQL Server, chociaż domyślna interpretacja obsługuje tylko punkty kodowe UCS-2 / Basic Multilingual Plane (BMP)) pozwala niektórym znakom nałożyć inny znak niebędący nakładką, gdy sąsiadują z nimi. Są one znane jako łączenie znaków .

Znaczenie:

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

Zwroty:

6

nie 2tak, jak większość ludzi oczekiwałaby od pojedynczego, dwubajtowego znaku. Może więc staramy się znaleźć jakąś postać, wykonując:

SELECT UNICODE(N'מַ֖');

który zwraca:

1502

Oczywiście funkcje UNICODEi ASCIIzwracają tylkoINT wartość pierwszego znaku dowolnego podanego ciągu. Ale wartość 1502 obejmuje tylko 2 bajty, co pozostawia 4 bajty nieuwzględnione. Patrząc na wartości binarne / szesnastkowe tego samego hebrajskiego „znaku”:

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

otrzymujemy:

מ
0x05DE  0xDE05B7059605

Teraz 0x05DE to szesnastkowa reprezentacja 1502, a 1502 to tylko „ מ ”. Kolejną część można podzielić na trzy zestawy 2-bajtowe: DE05 B705 9605 . Teraz wartości ciągów Unicode są przechowywane w Little Endian, co oznacza, że ​​kolejność bajtów jest odwrócona. Jeśli zmienimy każdy z tych trzech zestawów, otrzymamy:

05DE (znak podstawowy) 05B7 0596 (nierozliczone dla 4 bajtów).

Dobrze. Co się stanie, jeśli usuniemy tę podstawową postać?

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

Zwraca dwa pozostałe znaki (nie jest to łatwe do zobaczenia tutaj, więc podałem następujący wiersz jako nagłówek w celu zwiększenia rozmiaru czcionki; możesz również uruchomić powyższe REPLACE aby je zobaczyć):

Usunięcie מ z מַ֖ pozostawia dwa znaki na dole: ַ֖

Dlatego musimy usunąć każdy pojedynczy punkt kodowy, który jest jednym z tych „dodatkowych” łączących znaków (znalezionych na stronie: http://unicode-table.com/en/search/?q=hebrew ) i to nas opuści z podstawowymi postaciami. Możemy to zrobić poprzez:

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;

Następnie możemy przetestować go z oryginalnym tekstem w następujący sposób:

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

SELECT dbo.RemoveHebrewAccents(@Hebrew);

Zwroty:

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


Dodatkowe uwagi:

  • Technicznie istnieje zestaw punktów kodowych między 64298 a 64334, które mają wbudowane w postać pewne samogłoski i „akcenty” wymowy. Jeśli trzeba je obsłużyć, może to być drugi etap funkcji polegającej na prostej zamianie tych znaków.

  • Wygląda na to, że te akcenty, znaki interpunkcyjne itp. Punkty kodowe pasują tylko podczas korzystania z sortowania binarnego. Nawet używanie Hebrew_100_CS_AS_KS_WS_SCnie pasowało do nich. Ale dodaje zadziałały: Hebrew_BIN, Hebrew_BIN2, Latin1_General_BIN, i Latin1_General_BIN2. W funkcji skończyłem używać Hebrew_BIN2. Należy pamiętać, że podczas korzystania z zestawień binarnych, chyba że istnieje szczególna potrzeba użycia starszych _BINzestawień, należy używać tylko nowych _BIN2zestawień.

  • Dla każdego, kto jest ciekawy, hebrajski przykładowy tekst to Bereiszi 1: 1 (jest to również pierwsze słowo po prawej stronie, ponieważ hebrajski jest czytany od prawej do lewej; w języku angielskim będzie to jednak „Księga Rodzaju 1: 1” to nie jest bezpośrednie tłumaczenie tego słowa, tylko nazwa pierwszej księgi Tory / Biblii; bezpośrednie tłumaczenie to „na początku”):

    Na początku stworzenia Boga przez niebo i ziemię

  • 2015-01-19: Znalazłem świetne zasoby, które wyjaśniają zarówno łączenie postaci, jak i hebrajski zestaw znaków:

Solomon Rutzky
źródło
@Kin Thanks! (jeszcze raz :). Zobaczmy, jak długo twój komentarz przetrwa tym razem ;-D (zwróć uwagę na nasz „proces” oczyszczania duchów: nie miało to mieć żadnych niegrzecznych ani złośliwych implikacji, a ta buźka z halo dowodzi, że 😇 tak jak ten uśmiechnięty kot 😺)
Solomon Rutzky
1
i znowu uczę się czegoś nieoczekiwanego z twoich odpowiedzi. Ładny!
Max Vernon
1
Łał! Wrzucona ładna odpowiedź lingwistyczna z doskonałym opisem obsługi kodowania! Dzięki, Solomon!
Mike Williamson
1

To interesujący problem, z którym kiedyś miałem do czynienia przy pracy z japońskimi postaciami. Uderzyłem w kawałek ceglanego muru, próbując zlokalizować twoje problematyczne postacie, chociaż mam nadzieję, że to pomoże ci gdzieś je znaleźć.

Najpierw umieściłem wszystkie NCHAR w tabeli:

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

Następnie zlokalizowałem jeden z nieakcentowanych znaków:

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

Następnie zlokalizowałem zakres znaków, w których znajdują się hebrajskie znaki:

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

Ale próbując znaleźć akcentowane znaki, które chcesz, wydają się nie pojawiać, z wyjątkiem jednego trafienia w kodzie 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

Patrząc na otaczające znaki, nie mogę tak naprawdę zidentyfikować żadnego innego dopasowania do twojego tekstu.

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

Wiele z nich wydaje się rzucanych jak te mgliste małe prostokąty czegokolwiek.

Ponownie przepraszam, że to nie jest rozwiązanie, ale mam nadzieję, że to pomoże.

Erik Darling
źródło
1
Odp: „Próbuję znaleźć akcentowane znaki, które chcesz, nie wydają się pojawiać”, to dlatego, że nie istnieją ;-). Wyjaśniam bardziej szczegółowo w mojej odpowiedzi, ale w zasadzie jest to postać podstawowa z jedną lub dwiema nakładającymi się postaciami, które zajmują tę samą widoczną pozycję co postać podstawowa.
Solomon Rutzky,
3
To jest naprawdę świetne. Nigdy bym nie pomyślał, że te znaki są oddzielone od postaci. Dzięki.
Erik Darling,
1

Użyłem tabeli liczb. Istnieje wiele postów wyjaśniających, co to jest, dlaczego jest to przydatne i jak skutecznie je zdobyć.

Nie używam żadnej wbudowanej funkcji do konwersji znaków akcentowanych na nieakcentowane odpowiedniki. Zamiast tego tworzę listę odnośników, którą wypełnisz wymaganymi konwersjami. Oczywiście będziesz musiał użyć nvarchari zdefiniować swoje tłumaczenia N'x'.

Dzięki temu postowi dla wiersza konkatenacji wiersza.

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
źródło
Michael, hebrajski tak naprawdę nie działa w ten sposób. To nie są naprawdę „znaki diakrytyczne” w taki sam sposób, są to: Ü ö ò ô å Ä Å É ï. Dlatego standardowa metoda tłumaczenia / mapowania nie będzie działać.
Solomon Rutzky,
0

Oto, co zadziałało, jeśli ktoś w przyszłości chce.

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

Odszyfrowano
źródło