2 votes

Groovy : Comment vérifier si une liste contient des éléments d'une autre liste qui inclut le format regex ?

On m'a donné deux listes et je dois vérifier si des éléments de la liste des sites se trouvent dans la liste des sites ignorés. Lorsque j'exécute le code ci-dessous, il n'imprime que google.co.uk, mais ne devrait-il pas également imprimer amazon.co.uk et groovy-lang.org ?

Quelqu'un pourrait-il expliquer pourquoi il n'y a pas

def ignoredSites = ["www.amazon.com", /amazon.co.*/, /www.scala-lang.org/,/google.co.uk/, ~/htt(p|ps):\/\/www\.amazon\.co.*/, "groovy-lang.org"]
def sites = ["amazon.co.uk", ~/groo{2}vy-lang\.org/, "google.co.uk", "amazon.com", ~/scala.*/]

sites.each { site ->
    ignoredSites.contains(site) ? println("Ignored: ${site}") : ""
}

2voto

user987339 Points 3802

Tout d'abord, vous mélangez les expressions rationnelles et les chaînes de caractères dans les tableaux. Je vous suggère de les avoir dans des listes séparées. Deuxièmement, faites attention aux chaînes de caractères groovy slashy.

J'ai modifié votre code pour que vous puissiez voir cordes slashy (amazon.co.*, www.scala-lang.org, google.co.uk) sont en fait interprétés comme des chaînes de caractères et non comme des regex comme prévu.

Et dans votre cas, puisque vous mélangez regex et chaînes de caractères dans des tableaux, la vérification doit être faite différemment :

def ignoredSites = ["www.amazon.com", /amazon.co.*/, /www.scala-lang.org/,/google.co.uk/, ~/htt(p|ps):\/\/www\.amazon\.co.*/, "groovy-lang.org"]
def sites = ["amazon.co.uk", ~/groo{2}vy-lang\.org/, "google.co.uk", "amazon.com", ~/scala.*/]

println '==========sites============'
sites.each { site ->
  println site.toString() + " == "+ site.class
}
println '==========ignoredSites============'
ignoredSites.each { site ->
  println site.toString() + " == "+ site.class
}
println '======================'

sites.each { site ->
     if(site.class.equals(java.util.regex.Pattern)){
       ignoredSites.each{ is ->
         if(is.class.equals(java.lang.String)){
           if(is.matches(site)) println("Ignored: ${site}") //string = regex
         } else {
           //can't match 2 regex
         }
       }
     } else {
       ignoredSites.each{ is ->
         if(is.class.equals(java.lang.String)){
           if(is.equals(site)) println("Ignored: ${site}") //string = regex
         } else {
           if(site.matches(is)) println("Ignored3: ${site}") //string = regex
         }
       }
     }
}

Modifié

Si vous exécutez le code, en imprimant les types d'éléments, vous remarquerez la chose suivante :

==========sites============
amazon.co.uk == class java.lang.String
groo{2}vy-lang\.org == class java.util.regex.Pattern
google.co.uk == class java.lang.String
amazon.com == class java.lang.String
scala.* == class java.util.regex.Pattern
==========ignoredSites============
www.amazon.com == class java.lang.String
amazon.co.* == class java.lang.String
www.scala-lang.org == class java.lang.String
google.co.uk == class java.lang.String
htt(p|ps)://www\.amazon\.co.* == class java.util.regex.Pattern
groovy-lang.org == class java.lang.String
======================

Ainsi, amazon.co.uk ne correspond pas, car l'expression régulière qui devrait le faire correspondre :

amazon.co.* == class java.lang.String

est interprété comme un String par le groovy, à cause des strings slashy. D'un autre côté

groo{2}vy-lang\.org == class java.util.regex.Pattern

est une regex, mais {2} dans celui-ci, signifie que o apparaît exactement 2 fois. En bref, groo{2}vy-lang\.org correspondra à grooovy-lang.org (notez trois o là-dedans).

2voto

Paul King Points 81

Il serait plutôt inhabituel qu'un site soit un modèle, mais je suppose que c'est ce que vous vouliez dire :

def ignoredSites = ["www.amazon.com", /amazon.co.*/, /www.scala-lang.org/,/google.co.uk/, ~/htt(p|ps):\/\/www\.amazon\.co.*/, "groovy-lang.org"]
def sites = ["amazon.co.uk", ~/gro{2}vy-lang\.org/, "google.co.uk", "amazon.com", ~/scala.*/]

sites.findAll { site ->
    ignoredSites.find{ it == site || (site in String && site.matches(it) || (it in String && it.matches(site))) }
}.each{ println "Ignored: $it" }

2voto

sensei Points 551

En fait, je ne suis pas d'accord avec la réponse acceptée et cela ressemble au piège dans lequel l'interviewer veut vous faire tomber.

Pour vérifier cela, vous pouvez simplement changer ~/groo{2}vy-lang\.org/ à ~/gro{2}vy-lang\.org/ et voyez par vous-même que "groovy-lang.org" ne seront toujours pas ignorés.

Cela s'explique par le fait que java.util.Collection.contains() n'essaye pas d'être intelligent (probablement parce qu'il n'est pas écrasé par Groovy) et vérifie simplement, dans ce cas particulier, l'égalité (comme définie aquí ).

Así que "groovy-lang.org" ==~ /gro{2}vy-lang.org/ (le motif correspond) mais "groovy-lang.org" != ~/gro{2}vy-lang.org/ (ils ne sont pas des objets égaux et vérité groovy ne résume pas ce cas particulier).

Le test "ignorer" est basé sur l'égalité des objets, et non sur la correspondance des modèles comme l'interviewer vous a probablement volontairement induit en erreur.

J'espère que cela vous aidera, et que je ne me trompe pas.

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