Estrarre valori da una stringa

venerdì 11 aprile 2008 - 16.41

TaiChi Profilo | Junior Member

Salve a tutti,

ho questo problema da risolvere,

ho una stringa dalla quale devo estrarre dei valori con i quali aggiornare un db.

I valori sono racchiusi tra { } e [ ] in un determinato ordine che a me serve mantenere e che però non è costante, mi spiego con un esempio:

080107 * {Introduzione a Matteo} [si pp.175-7 §§1-10] * [Matteo 1-6] * [Matteo 5:1-20]*{Perché gli esseri umani muoiono?} * [rs pp.232-4 §3]*{In quali modi ci aiuta lo spirito santo di Dio} * {Fornite le spiegazioni necessarie} * [be p.228 §2-3]

080114 * {Provate diletto nella Parola di Dio} * [be p.9 §§1-5] * [Matteo 7-11] * [Matteo 10:1-23] * {Perché vale la pena di essere onesti} * {Dove sono i morti, e in che condizione si trovano?} [rs p.234 §4 - p.236 §2] * {Vi è implicato il cuore}*} * [be p.228 §§4-6]*229§1]

080121 * {Leggere la Bibbia ogni giorno} * [be p.10 §1 - p.12 §3] * [Matteo 12-15] * [Matteo 14:1-22] * {Perché ...tradizionali del lutto?}[rs p.236§3-237§7] * {Chi è cos'è l'anticristo?} * st?} * {Informativo per l'uditorio}*} * [be p.230 §§1-6]

080128 * {"Prestate attenzione a come ascoltate"} * [be p.13 §1 - p.14 §5] * [Matteo 16-21] * [Matteo 17:1-20] * {Come rispondere a chi ha idee errate sulla morte}[rs p.238 §§1-3]*104 ¶1] * {Cose che i cristiani considerano sacre} * {Rendete informativo il discorso facendo ricerche}[be p.231 §§1-3]

Come si vede le [ ] non sono sempre nella stessa posizione ma a serve assolutamente sapere in che posizione sono perchè questo determina quali campi del db devono esser aggiornati.

Ho provato usando le regular expression per isolare tutti i valori singolarmente ma così facendo perdo la posizione relativa quindi non va bene.

Pensavo a due soluzioni

Prima soluzione
Scorrere la stringa da cima a fondo intercettando sia le { } che le [ ] ed
estrarle

Seconda soluzione, che è una variante della prima
Estrarre delle sottostringhe che vadano da 080107 fino al carattere prima
di 080114 (sono date quindi sono valori uguali solo nel formato) e
ripetere l'operazione precedente.

Memorizzare il tutto in una matrice ed aggiornare il db.

In entrambi i casi non so come fare e ho bisogno del vostro aiuto.

Queste sono le mie idee ma accetto suggerimenti su metodi alternativi.

Grazie in anticipo.
Alessio Forconi

freeteo Profilo | Guru

ciao,
ti faccio 2 domande che vengono in mente al vedere il testo che hai postato:

- l' "*" è un separatore?
- le righe vanno a capo tramite un "\r\n" (VbCrlf) ?

Se sai quali sono i separatori di riga e di colonna, puoi pensare anche di leggere il file tramite "ReadLine" e fare degli split di quello che hai trovato con "*", in modo da avere un array, in questo modo:
using (TextReader reader = File.OpenText("..file..")) { string riga; string[] valori; while (!string.IsNullOrEmpty(riga = reader.ReadLine())) { valori = riga.Split('*'); //--- adesso tu sai le posizioni e decidi cosa fare ..... }
una cosa di questo genere...

ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

TaiChi Profilo | Junior Member

>ciao,
>ti faccio 2 domande che vengono in mente al vedere il testo che
>hai postato:
>
>- l' "*" è un separatore?
No, sono caratteri che non mi servono.
In effetti tutta la stringa è il risultato di una codifica dei byte di un file che conteneva dei caratteri ascii 0 con la conseguenza che non potevo leggere niente, dopo aver letto i byte ho sostituito quel carattere con *, infatti ce ne sono molti di più nella stringa ma non mi servono.

>- le righe vanno a capo tramite un "\r\n" (VbCrlf) ?
In realtà le righe non ci sono ma sono una riga unica, le ho messe così per una maggior leggibilità

Grazie Matteo.

Alessio Forconi

aiedail92 Profilo | Expert

Ciao

se quello di cui hai bisogno è poter ottenere tutti i valori compresi fra [] e {}, e memorizzare l'ordine in cui si presentano, le Regular Expressions fanno proprio al caso tuo: utilizzi una regex colla quale catturi tutti i valori compresi fra {} e [] salvando il risultato in un MatchCollection, quindi sfrutti le proprietà di ogni singolo Match nella collection per ottenere l'indice, il valore e il tipo (quandra o graffa) di ciascuno:

Regex regex = new Regex(@"{.*?}|\[.*?]", RegexOptions.Singleline); MatchCollection matches = regex.Matches(text); foreach (Match match in matches) { match.Value; // Il valore ottenuto (incluse le parentesi) match.Index; // L'indice in base 0 del match match.Length; // La lunghezza del match ottenuto if (match.Value[0] == '{') { //Il match è racchiuso fra graffe } else { //Il match è racchiuso fra quadre } }

Luca

TaiChi Profilo | Junior Member

Grazie Luca, a prima vista sembra proprio quelloche cercavo, domani la provo e ti saprò dire.

Per la verità avrei bisogno anche di isolare, secondo lo stesso criterio di ordine relativo anche le date, posso chiederti di inserire anche queste nella regex? Io non so pproprio da che parte cominciare con le regex.

Grazie comunque anche per quello che hai fatto finora, tu e anche gli altri volenterosi.


>Ciao
>
>se quello di cui hai bisogno è poter ottenere tutti i valori
>compresi fra [] e {}, e memorizzare l'ordine in cui si presentano,
>le Regular Expressions fanno proprio al caso tuo: utilizzi una
>regex colla quale catturi tutti i valori compresi fra {} e []
>salvando il risultato in un MatchCollection, quindi sfrutti le
>proprietà di ogni singolo Match nella collection per ottenere
>l'indice, il valore e il tipo (quandra o graffa) di ciascuno:
>
>Regex regex = new Regex(@"{.*?}|\[.*?]", RegexOptions.Singleline);
>
>MatchCollection matches = regex.Matches(text);
>
>foreach (Match match in matches)
>{
> match.Value; // Il valore ottenuto (incluse le parentesi)
> match.Index; // L'indice in base 0 del match
> match.Length; // La lunghezza del match ottenuto
>
> if (match.Value[0] == '{')
> {
> //Il match è racchiuso fra graffe
> }
> else
> {
> //Il match è racchiuso fra quadre
> }
>}
>
>Luca

Alessio Forconi

aiedail92 Profilo | Expert

Ho aggiunto alla regex il match delle date (il formato è yymmdd vero?)

Nella regex sono inseriti anche dei gruppi di acquisizione, di modo che quando viene eseguito il match di una data, il giorno, il mese e l'anno vengono inseriti in questi gruppi di acquisizione per essere recuperati più velocemente.

La regex è questa:

@"{.*?}|\[.*?]|(?<year>\d{2})(?<month>0[1-9]|1[012])(?<day>0[1-9]|[12][0-9]|3[01])"

aggiorno il codice che ti ho dato l'altra volta:

Regex regex = new Regex( @"{.*?}|\[.*?]|(?<year>\d{2})(?<month>0[1-9]|1[012])(?<day>0[1-9]|[12][0-9]|3[01])", RegexOptions.Singleline); MatchCollection matches = regex.Matches(text); foreach (Match match in matches) { match.Value; // Il valore ottenuto (incluse le parentesi) match.Index; // L'indice in base 0 del match match.Length; // La lunghezza del match ottenuto switch (match.Value[0]) { case '{': //il match è racchiuso fra graffe break; case '[': //il match è racchiuso fra quadre break; default: //il match è una data //Ottiene il giorno match.Groups["day"]; //Ottiene il mese match.Groups["month"]; //Ottiene l'anno match.Groups["year"]; break; } }

Luca

TaiChi Profilo | Junior Member

Grazie, sei stato molto gentile, io invece ho modificato così:

Regex regex = new Regex(@"\b\d{6}\b |{.*?}|\[.*?]", RegexOptions.Multiline);

MatchCollection matches = regex.Matches(text);

foreach (Match match in matches)
{
match.Value; // Il valore ottenuto (incluse le parentesi)
match.Index; // L'indice in base 0 del match
match.Length; // La lunghezza del match ottenuto

if (match.Value[0] == '{')
{
//Il match è racchiuso fra graffe
}
else if (match.Value[0] == '[')
{
//Il match è racchiuso fra quadre
}
else
{
//Il match è racchiuso fra quadre
}
}

ma la tua soluzione è interessante per la possibilità per i gruppi di acquisizione che immagino dovrei poter usare per estrarre le date, giusto?

Solo che adesso devi spiegarmi come fare?

Ho cercato in giro dei manuali delle Regular Expression ma in taliano non ci sono, ho trovato solo qualche guida molto molto generica, tu ne conosci?

grazie ancora.
Alessio Forconi

aiedail92 Profilo | Expert

Avevo inserito una regex un po' più complessa per evitare di fare il match di date inesistenti (come giorni oltre il 31 o mesi oltre il 12)

I gruppi di acquisizione vengono creati o inserendo la parte da catturare semplicemente fra parentesi tonde; in questo modo i gruppi di cattura vengono salvati in ordine numerico, a partire da 1. Altrimenti puoi salvarli assegnando un nome al gruppo, come ho fatto io prima, con questa sintassi: (?<nomeGruppo>Match)

É poi possibile riutilizzare i gruppi di acquisizione sia da codice, ottenendoli con match.Groups[indice], o match.Groups["nomeGruppo"], sia nella stessa regex, per eseguire il match di una stessa stringa acquisita in precedenza. In questo secondo caso li puoi richiamare tramite backreference con \indiceGruppo oppure con \k<nomeGruppo>, con indiceGruppo sempre a partire da 1

Per quanto riguarda manuali, non saprei darti indicazioni, potresti guardare su MSDN per i concetti base del motore e della sintassi regex di .net:

http://msdn2.microsoft.com/it-it/library/hs600312(VS.80).aspx
http://msdn2.microsoft.com/it-it/library/az24scfc(VS.80).aspx

Inoltre potrei rimandarti al blog di overclock:

http://blogs.dotnethell.it/Regulator/Category_1976.aspx

che sta tenendo alcune semplici "lezioni" di regex, anche se sono solo agli inizi...

Luca

TaiChi Profilo | Junior Member

Che dire...... Grazie!!!
Alessio Forconi

aiedail92 Profilo | Expert

Prego, è un piacere dare una mano dove posso

Luca
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5