2017-10-11 1 views
0

I "m en utilisant Rails 5 et Ruby 2.4. J'ai une fonctionComment appliquer gsub à une fonction?

my_function(str1, str2) 

qui renverra vrai ou faux donnés deux arguments de chaîne. Ce que je voudrais faire est d'une chaîne plus grande, par exemple

"a b c d" 

Je voudrais remplacer deux consécutifs « mots » (un mot par ma définition est une séquence de caractères suivie d'une limite de mot) avec la chaîne vide si l'expression

my_function(str1, str2) 

est évalué à vrai pour ces deux mots consécutifs. Ainsi, par exemple, si

my_function("b", "c") 

true, je voudrais la chaîne ci-dessus pour devenir

"a d" 

Comment puis-je faire?

Edit: Je suis notamment la sortie en fonction de la réponse de Tom Seigneur ...

Si je

def stuff(line) 
    matches = line.scan(/\b((\S+?)\b.*?\b(\S+?))\b/) 
    matches.each do |full_match, word1, word2| 
     line.delete!(full_match) if word1.eql?("hello") && word2.eql?("world") 
    end 
    end 

et la ligne est

"hello world this is a test" 

la ligne de chaîne résultante est

"tisisatst" 

Ce n'est pas tout à fait ce que j'attendais. Le résultat devrait être

" this is a test" 

Répondre

2

Edit: Ceci est une réponse mise à jour, en fonction des commentaires ci-dessous. J'ai laissé ma réponse originale en bas.

L'analyse d'une chaîne pour "deux mots consécutifs" est un peu difficile. Votre meilleure option est probablement d'utiliser la \b ancre dans une expression régulière, ce qui signifie une « limite de mot »:

string_to_change = "a b c d" 

matches = string_to_change.scan(/\b((\S+?)\b.*?\b(\S+?))\b/) 
    # => [["a b", "a", "b"], ["c d", "c", "d"]] 

... Lorsque la première chaîne est le « match plein » (y compris les espaces ou la ponctuation), les autres sont les deux mots.

Décomposer que regex:

  • \b signifie "limites de mot". J'ai placé un de chaque côté des deux cordes. Cette solution suppose que str1 et str2 sont tous les deux un seul mot. (S'ils contiennent des espaces, alors je ne sais pas quel comportement vous attendez?)
  • \S+? signifie "un ou plusieurs caractères non blancs". (Correspondant de manière non-avare, il s'arrêtera donc à première limite de mot).

Vous pouvez ensuite supprimer chaque « match plein » de la chaîne, si la méthode retourne vrai pour les deux mots:

matches.each do |full_match, word1, word2| 
    string_to_change.gsub!(full_match, '') if my_function(word1, word2) 
end 

Une chose qui est pas représenté ici (vous ne l'avez pas spécifiez ceci bien dans votre question ...) était comment manipuler des ficelles contenant trois mots ou plus. Par exemple, considérer les points suivants:

"hello world this is a test" 

Supposons que my_function(word1, word2) retours true seulement pour les paires: "world", "this" et "hello", "is".

Mon code ci-dessus ne regarder les paires: "hello", "world", "this", "is" et "a", "test". Mais peut-être il devrait en fait:

  1. Regardez tous paires de mots, à savoir tous les mots avec la gauche et côté droit.
  2. paires Suppression de mots à plusieurs reprises , à savoir après que la paire initiale: "world this" est retiré, la chaîne doit être re-numérisé puis "hello is" doit également être retiré?

Si d'autres améliorations sont nécessaires, veuillez les expliquer clairement dans une nouvelle question (si vous avez du mal à résoudre le problème vous-même).


réponse originale:

str1 = "b" 
str2 = "c" 
string_to_change = "a b c d" 

if my_function(str1, str2) 
    string_to_change.gsub!(/\b#{str1}\b\s+\b#{str2}\b/, "") 
end 

Décomposer que regex:

  • \b signifie "limite de mot". J'ai placé un de chaque côté des deux cordes. Cette solution suppose que str1 et str2 sont tous les deux un seul mot. (Si elles contiennent des espaces, alors je ne sais pas quel comportement vous attendez?)
  • \s+ signifie "un ou plusieurs caractères d'espacement". Vous souhaiterez peut-être modifier ce paramètre pour autoriser d'autres signes de ponctuation, par exemple une virgule ou un point. Une solution entièrement générique à ce problème pourrait en fait être:

.

string_to_change.gsub!(/\b#{str1}\b.(\B.)*#{str2}\b/, "") 

# Or equivalently: 

string_to_change.gsub!(/\b#{str1}\b(.\B)*.#{str2}\b/, "") 

.(\B.)* est la collecte au lieu chaque caractère, un à la fois, toujours vérifier que ce n'est pas la première lettre d'un mot (à savoir on passe par une limite non-mot).

+0

C'est une instruction 'if', pas une méthode. Oui, vous pouvez. –

+0

(Tant que vous définissez d'abord la méthode 'my_function' et que vous la renvoyez' true') essayez d'exécuter ceci dans une console. Ça fonctionne bien. –

+0

Merci, mais vous avez codé plusieurs choses dans votre solution. Je ne faisais que lister "b" et "c" comme exemple. Il y a un certain nombre de parametesr qui peuvent rendre ma fonction my_function (str1, str2) vraie. Et si on me donne juste une longue chaîne de texte?Comment puis-je faire fonctionner la logique alors? – Dave