Visualizzazione post con etichetta C#. Mostra tutti i post
Visualizzazione post con etichetta C#. Mostra tutti i post

venerdì 9 giugno 2017

Come calcolare la frequenza delle parole in un testo in C#

Calcolare la frequenza delle parole in un testo è un problema puramente accademico perché esistono già centinaia di programmi ed esempi di codice pronti per l'uso.
Dovendo comunque scrivere del codice, essendo pigro di natura, sono sempre alla ricerca della procedura più semplice e più breve possibile, ovviamente in C#
L'esempio contempla l'uso delle stopwords


//Testo da esaminare. Ho provato con files fino a 500MB senza attese fastidiose
string text = File.ReadAllText(path, Encoding.Default);

//caratteri separatori che identificano i limiti di una parola
char[] separators = new char[] { ' ', '\r', '\n', ',', '\\', '.', ';', ':', '(', ')', '"', '?', '!', '\'', '-', '«', '/' };

//lista delle parole contenute in text
List<string> words = text.Split(separators, StringSplitOptions.RemoveEmptyEntries).ToList();

//lista delle parole da escludere dal conteggio, le cosiddette stopwords, ad esempio congiunzioni, articoli e preposizioni
List<string> stopwords = File.ReadAllLines("StopWords.txt", Encoding.Default).ToList();

//Rimuove dalla lista le stopwords
//Non è possibili utilizzare Except perché fa una DISTINCT e annulla le frequenze
//Ho trovato molti forum in cui si chiede come utilizzare Contains in modo case insensitive
//O la documentazione è poco chiara o quei post si riferiscono a una versione di .NET antica
//La soluzione è semplice: utilizzare StringComparer
words.RemoveAll(item => stopwords.Contains(item, StringComparer.OrdinalIgnoreCase));

//Infine LINQ per contare le frequenze e presentarle in ordine discendente
var frequencies = words.GroupBy(n => n).Select(n => new { Value = n.Key, Count = n.Count() }).OrderByDescending(a => a.Count);

domenica 29 maggio 2016

Dettatura in italiano con Cortana

Sebbene quella del riconoscimento vocale sia ormai una tecnologia mainstream, il suo utilizzo è ancora piuttosto scarso a causa di un limite culturale o, più probabilmente, per la mancanza di interfacce vocali ben fatte.
Android e Apple Ios hanno i propri sistemi di dettatura integrati così come Windows, ma fino a Windows 7 l'unico modo per dettare in Italiano con i sistemi operativi Microsoft era installare un software commerciale come Dragon NaturallySpeaking.
Con Cortana e Windows 10 siamo passati alla seconda generazione dei motori di riconoscimento vocale, grazie all'utilizzo di modelli basati sulle reti neurali profonde (DNN).
Microsoft ha reso disponibile il riconoscimento vocale in decine di lingue, ma mancano le applicazioni che lo utilizzano tant'è che a oggi è possibile solamente dettare degli SMS con Windows phone oppure rivolgere delle domande a Cortana. Dettare delle email o un documento in Word è possibile in potenza ma di fatto manca ancora l'integrazione con Cortana.
Eppure le API ci sono. Basta avere Windows 10 e un collegamento a internet perché Cortana trascriva la nostra voce in tempo reale.
Le API di Cortana sono API WinRT, cioè pensate per le App Windows Store ma, esattamente come descritto nel post per le API OCR, è possibile utilizzarle in una normale applicazione desktop.
Qui un semplice progetto WPF che integra le API Windows.Media.SpeechRecognition con cui potrete giudicare l'accuratezza di Cortana.
Richiede Windows 10, l'accesso a Internet e l'input audio microfonico.
Quando terminate di parlare premete il pulsante Stop altrimenti il sistema produrrà un Timeout.
E qui l'esempio ufficiale di Microsoft

Update 23/06/2017: addin Office per la dettatura

lunedì 28 marzo 2016

Come utilizzare le API WinRT di Windows 10 in una applicazione desktop console C#

Sono entusiasta delle possibilità offerte dalle api WinRT di Windows 10 nelle applicazioni UWP, peccato usarle solo in app "sandboxed"
In realtà la maggior parte di queste API si possono utilizzare anche in applicazioni classiche desktop.
Vediamo ad esempio come utilizzare le librerie OCR in un programma a riga di comando che prende in ingresso un file contenente un'immagine e genera un file .txt con il risultato.

Con Visual Studio 2015 genera un nuovo progetto Visual C#->Windows->Classic Desktop->Console Application OCRConsole
  • Con il pulsante destro sul progetto fai Unload Project
  • Con il pulsante destro sul progetto fai Edit OCRConsole.csproj
  • Aggiungi <TargetPlatformVersion>10.0</TargetPlatformVersion> sotto <TargetFrameworkVersion>
  • Con il pulsante destro sul progetto fai Reload Project
  • Add Reference->Browse Windows.winmd da C:\Program Files (x86)\Windows Kits\10\UnionMetadata
  • Add Reference->Browse System.Runtime.WindowsRuntime da C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll. Nelle proprietà di System.Runtime.WindowsRuntime setta "Copy Local=False"
  • Se ottieni in compilazione un errore del tipo 'await' requires that the type 'Windows.Foundation.IAsyncOperation' have a suitable GetAwaiter method., verifica che il codice inizi con using System; Verifica anche che nel progetto il percorso System.Runtime.WindowsRuntime.dll sia assoluto

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Globalization;
using Windows.Graphics.Imaging;
using Windows.Media.Ocr;
using Windows.Storage;

namespace OCRConsole
{
    class Program
    {
        static private OcrEngine ocrEngine;
        static private string filePath;

        static async Task OCRAsync()
        {
            // Do any async anything you need here without worry
            // Load image from install folder.
            var file = await StorageFile.GetFileFromPathAsync(filePath);
            using (var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
            {
                // Create image decoder.
                var decoder = await BitmapDecoder.CreateAsync(stream);
                // Load bitmap.
                var bitmap = await decoder.GetSoftwareBitmapAsync();
                // Extract text from image.
                OcrResult result = await ocrEngine.RecognizeAsync(bitmap);
                // Display recognized text.
                File.WriteAllText(Path.ChangeExtension(filePath, "txt"), result.Text, Encoding.Default);
               
            }
        }

        static void Main(string[] args)
        {
            if (args.Length != 1)
            {
                Console.WriteLine("Usage: OCRConsole <filepath>");
                return;
            }

            filePath = args[0];
            if (!File.Exists(filePath))
            {
                Console.WriteLine("The file {0} doesn't exist", filePath);
                return;
            }
           
            // Init OCR engine with Italian language.
            ocrEngine = OcrEngine.TryCreateFromLanguage(new Language("it"));
            OCRAsync().GetAwaiter().GetResult();
           
        }
    }
}

Una volta per ottenere questo risultato ci voleva un SDK apposito, tonnellate di codice C++ e qualche giorno di sviluppo.