Braille translator in Excel

Îmi ești dragă ca lumina ochilor mei!

Probabil una din cele mai de presus expresii ale iubirii, rostite de multe ori fără semnificația profundă pentru mulți dintre noi.

La ora actuală se estimează că la nivel mondial sunt peste 36 de milioane de persoane nevăzătoare, din care aproximativ 100.000 în România. Sunt convins că există pe lumea asta multe aplicații software care-i ajută pe mulți să învețe să scrie și să citească în limbajul Braille. Vedem și noi astfel de simboluri prin din ce în ce mai multe locuri civilizate și nu le înțelegem semnificația.

Acest articol este o propunere de utilizare cu scopul de a genera text tipăribil în format Braille (vezi imagine 1). Există mai multe site-uri pentru a genera text Braille sau dispozitive electronice (foarte scumpe) de a scrie și citi Braille.

În cazul în care cineva de la o organizație a nevăzătorilor dispune de o astfel de imprimantă vă rog să testați și să mă contactați dacă este nevoie de îmbunătățiri asupra aplicației.

Fișierul poate fi deschis de la adresa: https://1drv.ms/x/s!ApGubfWFh8NurOhXSganso3njoqMmg?e=ZVGZ3o

Pentru a putea vedea cardurile generate ar fi indicat să activați partea de Turn on images.

În fișierul Excel am folosit noua funcție IMAGE() care permite aducerea unei imagini de pe internet într-o celulă și a efectua operațiuni cu ea.

În fișier, textul poate fi editat doar în zonele dedicate. Fișierul este creat în versiunea Excel din Microsoft 365 deci nu poate fi utilizat pe calculatoarele personale dacă nu dispuneți de o astfel de licență.

Fișierul este în editare publică, pentru a permite tuturor testarea. Orice utilizare în alte scopuri decât cele dedicate excedă responsabilitatea autorului.

UPDATE 17.08.2023

Mulțumesc tuturor celor care au distribuit acest articol. Am avut deosebita plăcere de a discuta cu oameni foarte faini legat de utilitatea acestui exercițiu și despre experiența lor cu lumea IT. În sinteză oamenii sunt bine, dar dacă fiecare dintre noi s-ar putea implica mai mult, ar fi și mai bine.

Cel mai mult m-a ajutat la validare și completare cu caractere românești domnul Aurel Pătru, profesor nevăzător la Liceul special Sfânta Maria din Arad.

Braille pentru ei este important pentru a putea citi în diferite locuri, dar cel mai mult îi ajută funcțiile de accesibilitate din sistemele de operare. Ei folosesc aceste funcții atât pe calculatoare/laptop-uri cât și pe telefoanele mobile. Au o nevoie de comunicare la fel ca toți ceilați și personal mă bucur că suntem împreună pe Internet sau alte canale de comunicare.

Astăzi am avut plăcerea să discut și cu dl Dan Patzelt de la http://www.tactileimages.org/ și mi-a povestit mult despre cum încearcă ei să ajute nevăzătorii și provocările tehnice și financiare pe care trebuie să le depășească.

Dincolo de exercițiul meu, care și-a atins scopul, utilitatea Excelului creat… nu este la fel de mare pe cât o credeam la început, pentru că ei scriu textul în clasic iar echipamentele de imprimare fac translatarea în alfabet Braille automat. :) (de asta probabil sunt și atât de scumpe).

Am actualizat fișierul Excel cu diactitice, cu specificarea faptului că sunt probleme la interpretarea literelor mari pentru diacritice. Acestea au același cod ASCII în Excel atât pentru litere mari cât și pentru cele mici… De asemenea, am modificat puți partea de printare în carduri pentru a răspunde cerinței de a avea maxim 32 x 18 carduri (cum le spun eu) pe o pagină A4.

END UPDATE

Povestea mai pe larg

Mă antrenez pentru Campionatul mondial de Excel eSports: https://www.fmworldcup.com/excel-esports/ Chiar vreau să ajung în primii 50 din lume, deci trebuie să trag tare.

Una din teme este manipularea caracterelor și codurilor prin funcțiile CHAR(), CODE(), UNICODE() și UNICHAR(). De asemenea sunt foarte importante funcțiile de parsare text și tabele, coloane, rânduri și reunificarea lor.

Studiind codurile unicode am descoperit și codurile pentru caracterele Braille. Fiecare simbol Braille reprezintă un set de puncte aranjate într-o matrice de 2×3. Aceasta oferă o structură uniformă pentru litere și cifre. Cu toate că majoritatea literelor majuscule sunt reprezentate printr-un singur simbol Braille, cifrele sunt reprezentate prin două simboluri alăturate. Acest lucru ajută la distingerea clară între cifre și litere într-un text Braille, reducând astfel confuzia și greșelile de interpretare.

Mai auzisem despre limbaj, dar acum aveam un motiv să abordez problema translatării cu adevărat. În foaia de calcul Sursa se află un tabel care conține ceea ce am găsit pe Braille ASCII – Wikipedia. Sunt mai multe simboluri dar am scos dintre ele caracterele speciale din Germană. De asemenea, în tabelul de pe Wikipedia sunt ceva probleme de reprezentare. Tot în sursa am introdus caracter cu caracter sursa imaginilor pentru carduri. Acestea sunt foarte importante pentru printare. Dacă folosești doar punctuația nu cred că este suficient pentru o imprimantă de acest gen. Pe coloana Dots se află punctuația în format 01 în care fiecare 1 reprezintă un punct de pe matricea de 2×3.

Propunerea mea de limbaj este una destul de simplă și am încercat să mă validez cu site-ul școlii: http://www.spdv.ro/braille/ care mi s-a părut a fi unul din cele mai stabile și sigure. Am folosit și site-uri pentru Engleză: https://wecapable.com/braille-translator/english-to-braille-converter/

Trebuie menționat că în sursă nu am diacriticele din limba română pentru că nu am găsit codurile Unicode pentru ele, neexistând o corespondență între vizual (setul de puncte – Dots) și unicode-ul zecimal de pe coloana DecUni.

Propunerea este simplă și prin faptul că nu este adaptată complexității metodelor de scriere din Engleză. M-am documentat pe site-ul https://en.wikipedia.org/wiki/English_Braille ca să înâeleg până unde se poate ajunge, dar mai este mult de lucru pentru acel format de scriere. Menționez că am interacționat cu „AI-urile” pentru a încerca să înțeleg mai repede și mai bine modul de scriere, dar dacă Bard este un pic mai răsărit ca iON () tot cu ChatGPT am ajuns să mă încurc cel mai tare. Problema majoră a lor este că oferă răspunsuri variate și contradictorii pentru aceleași întrebări. Problemele mele sunt legate de seturile de caractere Unicode, restul până la 256 din formatul Engleză (gradul 2), pentru care nu găsesc codurile cu echivalența, iar ChatGPT mi-a oferit variante și variante care mai de care mai lipsite de încredere, așa că pe moment am renunțat la ele. Dacă are cineva corespondența simbol – Unicode, Meaning vă rog să mă contactați.

Discutie cu ChatGPT

Principala provocare a fost să înțeleg de ce sunt diferențe de reprezentare între Engleză și Română. De exemplu pentru Engleză literele mari sunt prefixate de cardul 000001 (~6) iar în română de cardul 000101 (~46). Aceasta este și propunerea articolului. De asemenea, există tehnici de scriere în care se scrie totul cu litere mari și literele mici sunt prefixate cu card specific.

Cel mai greu din punct de vedere tehnic mi-a fost să reprezint numerele dintr-un text. Numerele și în română și în engleză (grad 1) sunt prefixate de cardul 001111 (~3456) echivalentul # (diez) din setul de caractere ASCII.

Pentru asta am studiat separate descompunerea unui text în litere, apoi ca să-l pot compara cu litera anterioară sau următoare l-am generat în coloană separate. Am identificat așadar când apare prima literă într-o coloană și în acest caz i-am introdus un # (diez).

Formula din D7: =IF(ISNUMBER(–B7);IF(ISNUMBER(–C7);B7;”#”&B7);B7)

Pentru a descompune un text în fiecare literă a sa, am folosit funcția MID() cu SEQUENCE()

Formula din B7: =MID(B4;SEQUENCE(LEN(B4));1)

Ca să pot ulterior să o folosesc într-o singură funcție cu LET() a trebuit să pun cele două coloane pe o singură coloană, în format linie cu line (rows) apoi să le transform într-un nou tabel cu Wraprows() ca să pot să aplic fiecărei linii formula inițială din D7 folosind funcția BYROW().

Surpriza a fost că în momentul în care am încercat să le unific, opțiunea de TOCOL() din două variabile de tip coloană nu funcționează, așa că a trebuit să unesc textul celor două coloane în formatul: col1&col2 (rezultat în L6) după care să aplic o altă funcție decât MAP() sau BYROW() care nu funcționează pentru splitare. Astfel ca să pot splita o coloană în mai multe coloane (linie cu linie) a trebuit să construiesc funcția din M6:

Care mi-a permis să fac un tabel cu două coloane și căruia să-i pot aplica un BYROW() cu funcția din D7.

=LET(
Data; L6#;
LenData; LEN(Data);
Rows; COUNTA(Data);
NumCols; 2;
Tabel; SEQUENCE(Rows; NumCols; 1; 1);
CharIndex; MOD(Tabel - 1; LenData) + 1;
CharPosition; INT((Tabel - 1) / LenData) + 1;
INDEX(MID(Data; CharIndex; 1); CharPosition; SEQUENCE(1; NumCols))
)

A fost hard dar sper să se fi meritat și să fie de ajutor cuiva!

Pentru întrebări și comentarii puteți folosi secțiunea dedicată din site!

O zi luminoasă tuturor!

CellColor() custom VBA function in Excel

Many years ago, I wrote an article about a custom function in VBA to sum multiple cells based on the font color. In this article, I propose an improved version of this function that allows the user to perform counting or summation based on the font color or background color.

This function works for the scenario where the cells or font are applied manually, not through conditional formatting. Explanations are provided at the end of the article.

To use this function, copy the function text from the article, open Excel, and then open the macro window by pressing the Alt+F11 key combination. Insert a new module and then paste the text from the clipboard.

Usage example:

VBA Function CellColor

Function CellColor(ColorRef As Range, cArea As Range, ColorType As Integer, Operation As Integer) As Integer
'CellColor function is designated to perform specific operations on range of cell by font or background color
    ' Parameters:
        ' ColorRef - Reference cell that containing specific format
        ' cArea - Area to be analyzed
        ' ColorType: 0 - Font; 1 - Background
        ' Operation: 0 - Count; 1 - Sum

'Defining variables
Dim rrcArea As Range
Dim rrRange As Range
nCells = 0
Set rrcArea = cArea


Select Case ColorType
    Case 0 ' Font
            vColor = ColorRef.Font.Color
            Select Case Operation
                Case 0 ' Count
                    For Each rrRange In rrcArea
                        If rrRange.Font.Color = vColor Then
                             nCells = nCells + 1
                        End If
                    Next rrRange
                Case 1 ' Sum
                    For Each rrRange In rrcArea
                        If rrRange.Font.Color = vColor Then
                             nCells = nCells + rrRange.Cells.Value
                        End If
                    Next rrRange
            End Select
    Case 1 ' Background
            vColor = ColorRef.Interior.Color
            Select Case Operation
                Case 0 ' Count
                    For Each rrRange In rrcArea
                        If rrRange.Interior.Color = vColor Then
                             nCells = nCells + 1
                        End If
                    Next rrRange
                Case 1 ' Sum
                    For Each rrRange In rrcArea
                        If rrRange.Interior.Color = vColor Then
                             nCells = nCells + rrRange.Cells.Value
                        End If
                    Next rrRange
            End Select
End Select

' Return results
CellColor = nCells

End Function

If you want to use this function for conditional formatted cells, you must save and call macro as UDF format.

Details about colors in conditional formatting form here: https://stackoverflow.com/questions/45122782/how-to-get-the-background-color-from-a-conditional-formatting-in-excel-using-vba and how to use it as UDF here: https://www.ablebits.com/office-addins-blog/store-custom-functions-excel/

Alternate way of counting or sum values from conditional formatting cells are Countif() and Sumif() on the same condition as format.

I hope it will be helpful to someone!

Un exemplu de WordCount în #Excel

Acest articol pune la dispoziția cititorilor o metodă de interpretare a textelor, extragere date și numărare a lor, folosind Microsoft Excel 365. De menționat că există instrumente superioare pentru această procedură, scopul meu de a folosi Excelul fiind unul de îmbunătățire a tehnicii de creare a formulelor complexe în Excel.

Tehnica wordcount este utilă pentru a evalua lungimea sau densitatea textului și poate fi utilizată în diferite contexte, cum ar fi analiza de texte sau de documente, pentru a evalua complexitatea sau pentru a verifica dacă un text se încadrează într-o limită de cuvinte. In mod obișnuit, această tehnică se bazează pe algoritmi de procesare a limbajului natural (NLP) și implică împărțirea textului în cuvinte și numărarea lor. În plus, se pot lua în considerare și alți factori, cum ar fi eliminarea cuvintelor de legătură sau a cuvintelor mici (cum ar fi „a”, „și”, „la” etc.), pentru a obține un număr mai precis.

Tehnica wordcount poate fi realizată manual, prin numărarea cuvintelor pe care le vedeți pe o pagină, sau poate fi efectuată automat, prin intermediul unor instrumente specializate sau software de procesare a textului. Rezultatul poate varia în funcție de tehnica și instrumentele utilizate.

În exemplul pe care vi-l propun am preluat primele 2000 de paragrafe de text din Preludiul Fundației de Isaac Asimov (pentru generația TikTok, este vorba despre o carte SF ). În fișierul pus la dispoziție aici, am păstrat doar primele 500 de linii.

Un instrument gratuit destul de interesant pentru wordcount poate fi accesat on-line la adresa: https://www.online-utility.org/text/analyzer.jsp

Comparativ rezultatele obținute pe primele 2000 de paragrafe:

Excel Text analyzer

Diferența de apariții pentru personajele principale este destul de mică, ceea ce îmi confirmă faptul că metoda aplicată în Excel este fezabilă. Problema este consumul de resurse și procesor pentru a interpreta cantități mari de text, Excel nefiind un instrument dedicat pentru analize volume mari de date.

Etapele implementării în Excel

Dacă ați descărcat fișierul WordCount – Excel 500.xlsx, veți observa că are 3 pagini și definită o singură formulă Lambda() în Name manager. Funcția de substituție fReplace2 am definit-o în articolul: Recursive Lambda() sau cum să scapi de „cârnații” de Substitute() de Substitute() în #Excel și este folosită cu scopul de a elimina caracterele speciale, diacritice și o serie de cuvinte de legătură. Cuvintele și caracterele sunt înregistrate în foaia de calcul Lambda. Lista de acolo poate fi modificată după caz. La momentul scrierii acestui articol este posibil ca problemele de performanță pe volume mari de text să fie cauzate de funcția Offset() utilizată în fReplace2, pentru că odată cu creșterea numărului de cuvinte de eliminat funcționează din ce în ce mai greu. Aici se impun ceva optimizări.

În foaia de calcul Textul începând cu celula C2 am utilizat funcția:

=LET(result; 
     UNIQUE(LOWER(TEXTSPLIT(
            fReplace2(A2;Lambda!$A$2;Lambda!$B$2);" "))); 
            FILTER(result;result<>""))

în care variabila result definită cu funcția LET() îmi permite ulterior filtrarea cu FILTER a rezultatelor care nu sunt nule, rezultate în urma înlocuirii acestora cu funcția fReplace2. Am folosit Lower() ca să transform toate cuvintele în litere mici, cu scopul de a preveni duplicarea pe aceleași cuvinte scrise în diferite formate și locuri ale propozițiilor.

Pentru cei care nu doresc să deschidă fișierul Excel, aici imaginea rezultată ca despărțire a textului cu TEXTSPLIT pe baza caracterului spațiu (” „).

Pe coloana B am folosit o funcție simplă de numărare a numărului de coloane rezultat ca urmare a execuției funcției de pe C2.

=COLUMNS(C2#)

Având în vedere că nu știu câte coloane sunt rezultate în urma delimitării textului din A2, modul în care am numărat coloanele trebuia apelat dinamic, de aceea am folosit C2# care reprezintă modul de apelare a rezultatului unei funcții dynamic array.

Numărul maxim de coloane mă ajută ulterior în centralizarea cuvintelor în mod dinamic în funcție de textul introdus de utilizator în coloana A.

În foaia de calcul Analiza am două zone: zona de cuvinte unice și zona de filtrare a cuvintelor pe baza unui anumit număr de apariții:

Funcția utilizată pentru a obține cuvintele unice este destul de complicată. Aici am primit puțin ajutor de la ChatGPT, dar destul de greu cu el. Cel puțin partea de INDIRECT nu a reușit să o folosească.

=UNIQUE(
             LET(result;
                    SORT(LET(
                             data;INDIRECT("Textul!R2C3:R"&COUNTA(Textul!A:A)-1&"C"&MAX(Textul!B:B)-2;FALSE);
                            rows;ROWS(data);
                            cols;COLUMNS(data);
                            flatten;SEQUENCE(rows*cols;1;0);
                            values;UNIQUE(INDEX(data;MOD(flatten;rows)+1;INT(flatten/rows)+1));
                           values));
FILTER(result;(LEN(result)>3)*(NOT(ISNUMBER(VALUE(result)))))))

În funcția prezentată, definesc o variabilă rezult care va prelua datele sortate din următorul calcul, și care este filtrată pe ultima linie cu un FILTER, prin care exclud cuvintele mai mici sau egale cu 3 caractere (a, și, la etc) și cele care sunt de tip număr.

În al doilea LET() definesc alte variabile fiecare cu calculele lor. Variabila data (mândria mea din această formulă) este definită printr-o funcție INDIRECT complet dinamică în funcție de numărul de linii de text din foaia Textul și maximul de coloane din coloana B. Având în vedere că nu știu care este numărul maxim de coloane am utilizat acest INDIRECT în formatul R1C1 style (parametrul FALSE) de la final.

Variabilele rows și cols devin oarecum redundante pentru că le am deja în indirect, dar le folosesc pentru a simplifica celelalte calcule.

Variabila flatten o folosesc pentru a defini o secvență liniară de numere echivalentă numărului de linii și coloane din data. Rolul său devine un fel de căutare în matrice prin INDEX-ul din variabila values care se raportează dinamic la numărul de linii și coloane din data.

Pe coloana B am funcția de numărare condiționată CountIF()

=COUNTIF(Textul!$C$1:$IJ$2500;A3)

Aici nu am mai construit dinamic cu INDIRECT tabelul de date. Cu indirect funcția ar arăta:

=COUNTIF(INDIRECT("Textul!R2C3:R"&COUNTA(Textul!A:A)-1&"C"&MAX(Textul!B:B)-2;FALSE);A3)

În celula G2: am introdus o valoare echivalentă numărului minim de apariții a unui cuvânt. Având în vedere că zona de cuvinte unice este formată dintr-un array dinamic și o coloană de calcul pe baza lui, nu putem sorta datele după numărul de apariții. În F3: am introdus funcția:

=SORT(FILTER(A2:B9350;B2:B9350>G2);2;-1)

Care asigură sortarea după coloana 2 din blocul specificat, în ordine descendentă (-1) și filtrează valorile după valorile mai mari decât cele specificate în G2.

Cam asta ar fi. Multă muncă, dar un antrenament mental bun. Dacă v-a plăcut sau nu, nu ezitați să îmi lăsați un feedback.

Sper să fie util cuiva!

Blog la WordPress.com.

SUS ↑