2011-04-16 3 views
1

J'essaye d'implémenter ceci dans un petit script de ruby, et l'ai testé sur http://www.rubular.com/, où il a fonctionné parfaitement. Je ne sais pas pourquoi il ne fonctionne pas dans le script réel.Quel est le problème avec ce RegEx?

Le RegEx: /(motion|links|sound|button|symbol)|(0.\d{8})|(\s\d{1}\s)|(\d{10} \ s)/

Le texte il est contre:

ID d'essai: 1 | Type d'essai: mouvement | Tour? 1 Temps de cliquage: 0.87913100 1302969732

ID de l'essai: 7 | Type d'essai: bouton | Tour? 0 Cliquez Heure: 0,19817800 1302987043

etc., etc.

Ce que je suis en train de saisir: Seuls les chiffres, et le seul mot après "Type d'essai". Donc pour la première ligne de l'exemple, je voudrais seulement que "1 motion 1 0.87913100 1302969732" soit retourné. Je veux également garder l'espace avant le premier nombre dans chaque essai.

Mon petit script Ruby:

File.open('log.txt', 'r') do |file| 
    contents = file.readlines.to_s 
    regex = Regexp.new(/(motion|links|sound|button|symbol)|(0\.\d{8})|(\s\d{1}\s)|(\d{10}\s)/) 
    matchdata = regex.match(contents).to_a 
    matchdata.each do |match| 
    if match != nil 
     puts match 
    end 
    end 
end 

Il ne sort que deux "1" cependant. Hmm ... Je sais qu'il lit le contenu du fichier correctement, et quand j'ai essayé une autre regex simplet ça a bien fonctionné.

Merci pour toute aide que je reçois ici !! :)

Répondre

3

Vous devez échapper les littéraux à l'intérieur de la regex, remplir d'autres littéraux manquants (comme Trick, \?, Click \ sTime :, supprimer certains des espaces, etc ...), et insérer des espaces regex le cas échéant ... à savoir

regex = Regexp.new(/(motion|links|sound|button|symbol)\s\|\sTrick\?\s*\d\s*Click\s+Time:\s+(0\.\d{,8})\s(\d{10}))/)

EDIT: imbrication entre parenthèses fixe dans la

originale
+0

Oh, je n'essaie pas de sortir tout le texte - j'essaie juste d'obtenir les chiffres et le mot après "trial trial". J'aurais dû le mentionner à l'origine, désolé! –

+0

@Jeff, c'est exactement mon point de vue ... le mot après le type d'essai et les numéros ont beaucoup plus de choses que le re doit correspondre. Vous ne pouvez pas prétendre qu'ils ne sont pas là ... "ruby" certainement pas. –

+0

Oh, j'ai vraiment du mal à comprendre l'expression régulière - je ne sais pas exactement comment éditer l'expression pour en tenir compte, mais ne pas les inclure dans les résultats ... –

4

Vous voulez utiliser String#scan

matchdata = contents.scan(regex) 

Aussi est correct Penington @ Mike, vous ne devriez pas avoir à faire la if match != nil si vous le faites correctement. Vous devez également nettoyer votre regex. Le caractère de pipe dans regex est un caractère spécial pour désigner le côté gauche OU le côté droit, et vous avez le caractère littéral que vous devez échapper.

+0

Cela aide une tonne, merci. Pourquoi l'analyse fait-elle une telle différence? Aussi, de cette façon, je continue à obtenir des résultats de tableau vides. Je sais que c'est probablement parce que je suis juste mauvais dans les expressions régulières, mais si je pouvais juste éliminer les taches de tableau vide cela résoudrait totalement mes problèmes ... savez-vous comment je ferais cela? –

2

Si vous savez que les données suivent un modèle particulier, il vous suffit de suivre ce modèle dans l'expression régulière, et ramasser les portions que vous voulez avec ().

/Trial ID: (\d+) \| Trial Type: (\w+) \| Trick\? (\d+) Click Time: ([\.\d]+) ([\.\d]+)/ 

Plus vous en savez sur les données, plus vous pouvez faire l'expression rationnelle. Si vous voyez quelques variations dans les données, et l'expression rationnelle ne correspond pas, alors détendez-vous le modèle:

  • Si l'ID Trail, ID Trail peut inclure un point décimal, utilisez [\.\d]+ au lieu de \d+.
  • Si l'espace peut être plus d'un, puis le remplacer par []+
  • Si l'espace peut être un onglet, ou peut être absent, utilisez \s* ou [ \t]*.
  • Si la partie Trial ID: peut apparaître comme une autre phrase, le remplacer par .*?,

et ainsi de suite.

Si vous n'êtes pas sûr combien d'espaces/onglets apparaissent, utilisez ceci:

/Trial\s*ID:\s*(\d+)\s*\|\s*Trial\s*Type:\s*(\w+)\s*\|\s*Trick\?\s*(\d+)\s*Click\s*Time:\s*([\.\d]+)\s+([\.\d]+)/ 
+0

Doux, merci. Donc, seulement ce que vous mettez entre parenthèses est réellement repris par l'expression rationnelle? Je n'ai pas réalisé ce haha. J'ai entré le motif que vous avez mis ici, ce qui est logique, et n'a obtenu aucun résultat ... hmm ... –

+0

Ensuite, peut-être que la chaîne a quelques variations. Par exemple, vous pouvez avoir deux espaces au lieu d'un, voire aucun, ou vous pouvez avoir un onglet. Vous n'avez peut-être pas de deux points, etc. Pouvez-vous comprendre quel genre de variations a votre chaîne? Ce que vous n'avez pas mis entre parenthèses apparaîtra comme faisant partie de '$ 0', qui représente la partie entière qui correspond. Les autres parties entre parenthèses seront respectivement de "1 $", "2 $", ... – sawa

+0

Merci beaucoup, avec votre aide et celle des autres, je l'ai résolu. Voici ma dernière regex: Regexp.new (/.*? ID d'essai: (d +). *? Type d'essai: (motion | links). *? Trick \? (\ D +). *? Click Time: (0 \. \ d {8}) \ s (\ d {10}) /) –

1

C'est un de ces moments que d'essayer de tout dans un grand regex vous fait travailler trop dur. Simplifier les choses:

ary = [ 
    'Trial ID: 1 | Trial Type: motion | Trick? 1 Click Time: 0.87913100 1302969732', 
    'Trial ID: 7 | Trial Type: button | Trick? 0 Click Time: 0.19817800 1302987043' 
] 

ary.each do |li| 
    numbers = li.scan(/[\d.]+/) 
    trial_type = li[/Trial Type: (\w+)/, 1] 

    puts "%d %s %d %f %d\n" % [numbers.first, trial_type, *numbers[1 .. -1]] 
end 
# >> 1 motion 1 0.879131 1302969732 
# >> 7 button 0 0.198178 1302987043 

modèles sont puissants Regex, mais les gens pensent qu'il est macho de tout faire dans une grande ligne. Vous devez peser cela avec le travail supplémentaire nécessaire pour assembler la regex en premier lieu, et le maintenir si quelque chose change dans le texte analysé plus tard.