2 votes

Comment écrire une expression régulière capable de correspondre à une ou deux lignes de texte ?

J'essaie de faire correspondre un texte qui peut être à une ou deux lignes. J'aimerais pouvoir traiter les deux scénarios de manière efficace. La chaîne de texte sera formatée de manière cohérente et contiendra plusieurs tabulations. J'essaie de faire les correspondances en ruby. Le texte est le suivant :

Ligne unique :

#3  Hello Stormy    Scratched - Reason Unavailable                           11:10 AM ET 

Deux lignes :

#3  Hello Stormy    Scratched - Reason Unavailable                            11:10 AM ET   
                    Scratch Reason - Reason Unavailable changed to Trainer     2:19 PM ET  

J'ai dû utiliser des espaces pour formater les chaînes ici, mais le texte réel utilise des tabulations pour séparer les différentes sections : numéro et nom, rayé et raison et heure.

Exemple de sortie :

Une ligne : #3 Hello Stormy Scratched - Reason Unavailable 11:10AM ET

Deux lignes #3 Hello Stormy Scratché - Raison indisponible changé pour Entraîneur 2:19PM

Note : Idéalement, la sortie sur deux lignes devrait inclure le numéro et le nom de la première ligne.

Je suis capable de construire une expression qui correspond aux différentes sections, mais les tabulations, la deuxième ligne et la nécessité d'avoir le numéro et le nom du cheval sur la sortie de deux lignes me posent des problèmes.

2voto

the Tin Man Points 69148

Vous n'avez pas besoin d'une expression régulière sophistiquée pour faire ce que vous voulez, il vous suffit de savoir comment procéder.

La méthode Enumerable de Ruby s'appelle slice_before qui prend une expression régulière, utilisée pour déterminer quels éléments du tableau sont regroupés. Array hérite de Enumerable. Par exemple :

text = '#3  Hello Stormy    Scratched   -   Reason Unavailable          11:10 AM ET
#3  Hello Stormy    Scratched   -   Reason Unavailable          11:10 AM ET
                        Scratch Reason  -   Reason Unavailable changed to Trainer   2:19 PM ET
'

data = text.split("\n").slice_before(/\A\S/).to_a

require 'pp'
pp data

Sorties :

[["#3\tHello Stormy\tScratched\t-\tReason Unavailable\t\t\t11:10 AM ET"],
["#3\tHello Stormy\tScratched\t-\tReason Unavailable\t\t\t11:10 AM ET",
  "\t\t\tScratch\tReason\t-\tReason Unavailable changed to Trainer\t2:19 PM ET"]]

En d'autres termes, le tableau créé en divisant le texte sur "\n" est regroupé par lignes ne commençant pas par un espace blanc, ce qui correspond au modèle /\A\S/ . Toutes les lignes simples se trouvent dans des sous-ensembles distincts. Les lignes qui sont des suites de la ligne précédente sont regroupées avec cette dernière.

Si vous lisez un fichier à partir d'un disque, vous pouvez utiliser la fonction IO.readlines pour lire le fichier sous la forme d'un tableau, ce qui évite d'avoir à diviser le fichier.

Vous pouvez traiter ce tableau plus avant, si vous le souhaitez, pour reconstruire les lignes et les lignes de suite, en utilisant quelque chose comme :

data = text.split("\n").slice_before(/\A\S/).map{ |i| i.join("\n") }

Qui tourne data en :

["#3\tHello Stormy\tScratched\t-\tReason Unavailable\t\t\t11:10 AM ET",
"#3\tHello Stormy\tScratched\t-\tReason Unavailable\t\t\t11:10 AM ET\n\t\t\tScratch\tReason\t-\tReason Unavailable changed to Trainer\t2:19 PM ET"]

Si vous avez besoin de diviser chaque ligne en ses champs constitutifs, utilisez la fonction split("\t") . La manière de procéder pour les sous-réseaux est un exercice que vous pouvez faire, mais j'impliquerais map .


EDITAR:

...J'aime votre solution, mais j'obtiens une méthode non définie pour slice_before.

Essayez ceci :

require 'pp'
require 'rubygems'

class Array

  unless Array.respond_to?(:slice_before)
    def slice_before(pat)
      result = []
      temp_result = []
      self.each do |i|

        if (temp_result.empty?)
          temp_result << i
          next
        end

        if i[pat]
          result << temp_result
          temp_result = []
        end

        temp_result << i
      end
      result << temp_result

    end
  end

end

Appeler cela :

ary = [
  '#3  Hello Stormy    Scratched - Reason Unavailable                           11:10 AM ET',
  '#3  Hello Stormy    Scratched - Reason Unavailable                            11:10 AM ET',
  '                    Scratch Reason - Reason Unavailable changed to Trainer     2:19 PM ET',
]

pp ary.slice_before(/\A\S/)

On dirait que.. :

[
  ["#3  Hello Stormy    Scratched - Reason Unavailable                           11:10 AM ET"],
  ["#3  Hello Stormy    Scratched - Reason Unavailable                            11:10 AM ET",
   "                    Scratch Reason - Reason Unavailable changed to Trainer     2:19 PM ET"]
]

1voto

Steinar Points 2471

La procédure est simplifiée si l'on suppose que le caractère "#" n'apparaît nulle part ailleurs dans la chaîne de caractères. Dans ce cas, quelque chose comme ceci devrait suffire :

 /^#[^#]*/m

Une autre approche plus générique consiste à prendre en compte la première ligne commençant par #, et toutes les lignes suivantes commençant par un espace ou une tabulation :

 /^#.*?$(\n^[ \t].*?$)*/m

Si la ligne ne commence pas toujours par #, vous pouvez la remplacer par [^ \t] (pas d'espace ni de tabulation).

1voto

CaptainPete Points 2991

S'amuser avec les RE ! Ce n'est pas très pratique, mais il y a plusieurs types de stratégies d'appariement.

# Two-line example
s = <<-EOS
  #3\tHello Stormy\t\tScratched - Reason Unavailable\t\t\t11:10 AM ET\t
  \t\t\tScratch Reason - Reason Unavailable changed to Trainer\t2:19 PM ET
EOS
# allow leading/trailing whitespace, get the number, name, last reason and time
s =~ /\A\s*(#\d)\t+([^\t]+)(?:\t+.*)?(?:\t+(.*))\t+(\d+:\d+ (?:AM|PM) ET)\s*\Z/m
# ["#3", "Hello Stormy", "Scratch Reason - Reason Unavailable changed to Trainer", "2:19 PM ET"]
a = $1, $2, $3, $4

Remarque : cela suppose qu'il n'y ait qu'un seul message dans la chaîne que vous recherchez.
Note : non testé pour le cas d'une seule ligne :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X