2009-06-03 5 views
1

Je dois analyser un tas de statistiques à partir du texte, et ils sont tous formatés en nombres.Regex qui correspond à quelque chose avant un certain caractère?

Par exemple, ce paragraphe:

Un total de 81,8 pour cent de New York étudiants de la ville dans les classes 3 à 8 sont réunion ou supérieure à niveau scolaire en mathématiques normes, par rapport à 88,9 pour cent des étudiants dans le reste de l'État.

Je veux faire correspondre seulement les nombres 81 et 88, pas les ".8" ​​et ".9" qui suivent.

Comment est-ce que je peux faire ceci? J'ai entendu le terme back-reference ou look-aheads ou quelque chose comme ça. Est-ce que ça va aider?

J'utilise C#.

Editer: Il est nécessaire que j'obtienne le "3" et le "8" dans l'exemple ci-dessus. C'est juste un exemple simple, mais j'ai besoin de presque tous les chiffres.

+0

Les chiffres après la virgule sont statistiquement significatifs sur une grande population. J'utiliserais l'expression «pour cent» pour trouver les nombres relatifs. – Craig

+0

Craig - Je ne comprends pas ce que vous voulez dire - je l'ai juste pris comme exemple - mes nombres réels ne sont pas des pourcentages. Je dois juste enlever les caractères qui viennent après le "." et d'autres modèles, comme "e +". Ce n'était qu'un exemple très simple. –

Répondre

2

Si vous ne voulez pas traiter avec des groupes, vous pouvez utiliser un comme vous dites préanalyse; ce modèle trouve la partie entière de tous les nombres décimaux dans la chaîne:

Regex integers = new Regex(@"\d+(?=\.\d)"); 
MatchCollection matches = integers.Matches(str); 

matches contiendra 81 et 88. Si vous souhaitez correspondre à la partie entière de tous les numéros (décimal ou non), vous pouvez rechercher à la place des entiers qui ne commencent pas par un .:

Regex integers = new Regex(@"(?<!\.)\d+"); 

Cette fois-ci, correspond contiendrait 81, 3 , 8 et 88.

+0

Dans votre première regex, vous devriez mettre '\ d +' avant la paren finale pour ne pas avoir de faux positifs à la fin des phrases. –

+0

Excellent point. Je suis allé avec '\ d' puisque je me fous de combien il y en a. Merci pour la correction. – ojrac

+0

Dans votre deuxième bloc de code, quel genre de syntaxe est-ce? Je ne sais pas quoi?

0
/(\d+)\.\d/g 

Cela correspondra un nombre qui a une décimale qui suit (ce qui je pense est ce que vous voulez), mais ne capturera les chiffres avant la virgule. \d capturera seulement des nombres (mêmes que [0-9]), ainsi ceci rend ceci assez simple. Editer: Si vous voulez aussi le trois et le huit, vous n'avez même pas besoin de vérifier le nombre décimal. Edit2: Désolé, corrigé afin d'ignorer toutes les décimales.

/(\d+)(?:\.\d+)?/g 
+0

S'il vous plaît voir mon édition - Je dois obtenir tous les numéros, mais dépouiller les chiffres après la virgule (mes données réelles ont une précision folle) –

+0

Si j'utilise votre deuxième, je reçois le 9 et le 1, que je ne Je veux. –

3
/[^.](\d+)[^.]/ 

Comme il est indiqué ci-dessous il suffit d'utiliser MatchObj.Groups (1) pour obtenir le chiffre.

+0

Cela ne saisira-t-il pas aussi les chiffres qui suivent le point décimal? Pourrait mettre un [^.] À l'avant de cela. –

1

Essayez:

[0-9]*(?=[3]) 

Il utilise un Lookahead correspondre à des chiffres suivis d'une virgule.

C# Code:

Regex regex = new Regex("[0-9]+(?=[.])"); 
MatchCollection matches = regex.Matches(input); 
+1

Vous obtiendrez une entrée vide à chaque période, car vous correspondez à 0 ou plusieurs chiffres au lieu de 1 ou plus. –

+0

Merci, était pressé plus tôt et ne faisait pas vraiment attention – Stephan

0

Essayez d'utiliser /(\d+)((\.\d+)?)/

Cela signifie essentiellement correspondre à une séquence de chiffres et un point décimal en option avec une autre séquence de chiffres. Ensuite, utilisez MatchObj.Groups(1) pour la première valeur de correspondance, en ignorant la seconde.

1
[^.](\d+) 

votre exemple, cela correspondra à « 81 », « 3 », « 8 », « 88 »

Vous obtiendrez un caractère supplémentaire avant que vous obtenez votre numéro, mais vous pouvez juste couper cela dans votre code.

0

Ce n'est pas dans la langue que vous avez posée, mais cela peut vous aider à penser au problème.

$ echo "A total of 81.8 percent of New York City students in grades 3 to 8 are meeting or exceeding grade-level math standards, compared to 88.9 percent of students in the rest of the State." \ 
| fmt -w 1 | sed -n -e '/^[0-9]/p' | sed -e 's,[^0-9].*,,' | fmt -w 72 
81 3 8 88 

La première commande fmt demande aux commandes suivantes de considérer chaque mot séparément. La commande "sed -n" ne sort que les mots qui commencent par au moins un nombre. La seconde commande sed supprime le premier caractère non numérique du mot, et tout ce qui suit. La seconde commande fmt combine tout en une ligne.

$ echo "This tests notation like 6.022e+23 and 10e100 and 1e+100." \ 
| fmt -w 1 | sed -n -e '/^[0-9]/p' | sed -e 's,[^0-9].*,,' | fmt -w 72 
6 10 1 
2

solution complète C#:

/// <summary> 
/// Use of named backrefence 'roundedDigit' and word boundary '\b' for ease of 
/// understanding 
/// Adds the rounded percents to the roundedPercents list 
/// Will work for any percent value 
/// Will work for any number of percent values in the string 
/// Will also give those numbers that are not in percentage (decimal) format 
/// </summary> 
/// <returns>true if success, false otherwise</returns> 
public static bool TryGetRoundedPercents(string digitSequence, out List<string> roundedPercents) 
{ 
    roundedPercents = null; 
    string pattern = @"(?<roundedDigit>\b\d{1,3})(\.\d{1,2}){0,1}\b"; 

    if (Regex.IsMatch(digitSequence, pattern)) 
    { 
     roundedPercents = new List<string>(); 
     Regex r = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.ExplicitCapture); 

     for (Match m = r.Match(digitSequence); m.Success; m = m.NextMatch()) 
      roundedPercents.Add(m.Groups["roundedDigit"].Value); 

     return true; 
    } 
    else 
     return false; 
} 

A partir de votre exemple renvoie 81, 3, 8 et 88

Questions connexes