La mia stringa di tempo può essere in uno dei seguenti formati (x
e y
- numero intero numeri, h e m - simboli):
x
hy
mx
hy
my
Esempi:
- 1h 20m
- 45m
- 2h
- 120
Quale espressione regolare dovrei scrivere per ottenere x
e y
numeri da tale stringa?
risposte:
3 per risposta № 1Immagino che tu stia usando .NET a causa del tuo nome utente. :)
Penso che in questo caso sia più facile da usare TimeSpan.ParseExact
per questo compito.
È possibile specificare un elenco di formati consentiti (guarda qui per il formato di questi) e ParseExact
leggerà nel TimeSpan
in accordo con loro.
Ecco un esempio:
var formats = new[]{"h"h"", "h"h "m"m"", "m"m"", "%m"};
// I have assumed that a single number means minutes
foreach (var item in new[]{"23","1h 45m","1h","45m"})
{
TimeSpan timespan;
if (TimeSpan.TryParseExact(item, formats, CultureInfo.InvariantCulture, out timespan))
{
// valid
Console.WriteLine(timespan);
}
}
Produzione:
00:23:00
01:45:00
01:00:00
00:45:00
L'unico problema è che è piuttosto inflessibile. Gli spazi bianchi aggiuntivi nel mezzo non riusciranno a convalidare. Una soluzione più robusta che utilizza Regex è:
var items = new[]{"23","1h 45m", "45m", "1h", "1h 45", "1h 45", "1h45m"};
foreach (var item in items)
{
var match = Regex.Match(item, @"^(?=d)((?<hours>d+)h)?s*((?<minutes>d+)m?)?$", RegexOptions.ExplicitCapture);
if (match.Success)
{
int hours;
int.TryParse(match.Groups["hours"].Value, out hours); // hours == 0 on failure
int minutes;
int.TryParse(match.Groups["minutes"].Value, out minutes);
Console.WriteLine(new TimeSpan(0, hours, minutes, 0));
}
}
Ripartizione della regex:
^
- inizio della stringa(?=d)
- deve iniziare con una cifra (fai questo perché entrambe le parti sono contrassegnate come facoltative, ma vogliamo assicurarci che almeno una sia presente)((?<hours>d+)h)?
- ore (facoltativo, acquisizione in un gruppo con nome)s*
- spazio bianco (facoltativo)((?<minutes>d+)m?)?
- minuti (opzionale, cattura nel gruppo con nome, anche la "m" è opzionale)$
- fine della stringa
4 per risposta № 2
(d+)([mh]?)(?:s+(d+)m)?
È quindi possibile ispezionare i gruppi 1-3. Per i tuoi esempi quelli sarebbero
("1", "h", "20")
("45", "m", "")
("2", "h", "")
("120", "", "")
Come sempre, potresti voler usare delle ancore ^
, $
, b
...
1 per risposta № 3
Direi che la soluzione di mhyfritz è semplice, efficiente e buona se il tuo contributo è solo ciò che hai mostrato. Se hai mai avuto bisogno di gestire casi d'angolo, puoi usare un'espressione più discriminante:
^(d+)(?:(h)(?:s+(d+)(m))?|(m?))$
Ma può essere eccessivo ...
(sbarazzarsi di ^ e $ se è necessario rilevare tale modello in un corpo di testo più grande, ovviamente).
1 per risposta № 4
Prova questo: ^(?:(d+)hs*)?(?:(d+)m?)?$
:
var s = new[] { "1h 20m", "45m", "2h", "120", "1m 20m" };
foreach (var ss in s)
{
var m = Regex.Match(ss, @"^(?:(d+)hs*)?(?:(d+)m?)?$");
int hour = m.Groups[1].Value == "" ? 0 : int.Parse(m.Groups[1].Value);
int min = m.Groups[2].Value == "" ? 0 : int.Parse(m.Groups[2].Value);
if (hour != 0 || min != 0)
Console.WriteLine("Hours: " + hour + ", Mins: " + min);
else
Console.WriteLine("No match!");
}
0 per risposta № 5
in bash
echo $string | awk "{for(i=1;i<=NF;i++) print $i}" | sed s/[hm]/""/g