2010-07-21 4 views
1

Comment puis-je compter le nombre de mots entre deux mots?Comment puis-je compter le nombre de mots entre deux mots?

$txt = "tükörfúrógép banana orange lime, tükörfúrógép cherry árvíztűrő orange lyon 
    cat lime mac tükörfúrógép cat orange lime cat árvíztűrő 
    tükörfúrógép banana orange lime 
    orange lime cat árvíztűrő"; 

Les deux mots 'inondation tolérant' et 'drill miroir'
J'ai besoin de ce retour:
miroir inondation tolérant forage miroir forage miroir inondation tolérant
cerise chat chat lime orange,
foret banane orange, citron vert inondation tolérant la chaux chat orange

Maintenant, j'ai cette expression régulière:

preg_match_all('@((tükörfúrógép(.*)?árvíztűrő)(árvíztűrő(.*)?tükörfúrógép))@sui',$txt,$m); 

Répondre

7

Plusieurs choses que je dois signaler:

  1. Vous ne pouvez pas le faire dans un regex. Regex est un avant uniquement, l'ordre inversé nécessite le deuxième match de regex.
  2. (.*)?
  3. que vous utilisez, mais vous voulez dire (.*?)
  4. AQUÍ Pour corriger les matchs, vous devez vous assurer nuire à la limite gauche de votre expression ne peut pas se produire au milieu.
  5. Vous devez dénoter les limites de mots ( \b) delimiter autour de vos mots pour GARANTIR matchs de mots entiers. EDIT: Si, en théorie est correcte, cela ne fonctionne pas pour l'entrée Unicode dans PHP.
  6. Vous devez changer les paramètres régionaux hongrois PHP (il est Webster, non?) Avant d'appeler preg_match_all(), Parce que l'environnement local a une influence sur ce qui est considéré comme une limite de mot en PHP. EDIT: La signification de \b ne change pas en fait avec les paramètres régionaux sélectionnés.

Cela dit regex # 1:

 
(\btükörfúrógép\b)((?:(?!\1).)*?)\bárvíztűrő\b 

regex et # 2 est analogue, avec des mots délimiteurs juste renversées.

regex explication:

(    # match group 1: 
    \b   # a word boundary 
    tükörfúrógép # your first delimiter word 
    \b   # a word boundary 
)    # end match group 1 
(    # match group 2: 
    (?:   # non-capturing group: 
    (?!   #  look-ahead: 
     \1  #  must not be followed by delimiter word 1 
    )   #  end look-ahead 
    .   #  match any next char (includes \n with the "s" switch) 
)*?   # end non-capturing group, repeat as often as necessary 
)    # end match group 2 (this is the one you look for) 
\b    # a word boundary 
árvíztűrő  # your second delimiter word 
\b    # a word boundary 

MISE À JOUR: Avec une mauvaise chaîne prise en charge Unicode Pathétique PHP , vous serez obligé d'utiliser des expressions comme ceux-ci comme Remplacements pour \b:

$before = '(?<=^|[^\p{L}])'; 
$after = '(?=[^\p{L}]|$)'; 

Cette suggestion a été prise de another question

+0

Ce retour tableau vide: Array ([0] => Array() [1] => Array() [2] => Array()) – turbod

+0

PS: Eh bien, pour être tout à fait honnête - vous pouvez * le faire dans une regex, en concaténant regex # 1 et regex # 2 comme ça '# 1 | 2'. C'est à vous de voir si vous considérez l'expression qui en résulte vaut la peine. ;-) – Tomalak

+0

@turbod: Qu'est-ce qu'un simple \ 'rvíztűrő \ b' vous donne? – Tomalak

1

Au lieu d'une énorme confusion expression régulière, pourquoi ne pas écrire quelques lignes en utilisant différentes fonctions de chaîne?

Exemple:

$start = strpos($txt, 'árvíztűrő') + 9; // position of first char after 'árvíztűrő' 
$end = strpos($txt, 'tükörfúrógép', $start); 
$inner = substr($txt, $start, $end - $start); 
$words = preg_split("/[\s,]+/", $inner); 
$num = count($words); 

Bien sûr, cela va manger de la mémoire si vous avez une chaîne d'entrée gigantesque ...

+0

Désolé, mais cela ne fonctionne pas. – turbod

+0

Ah - qu'est-ce qu'il a fait? En regardant maintenant, un problème possible qui vient à l'esprit est que vos caractères drôles accentués ne sont probablement pas dans l'ensemble ASCII et donc la longueur de 'árvíztűrő' peut être plus de 9 ... – Kricket

3

Pour compter les mots entre deux mots que vous pouvez facilement utilisation:

count(split(" ", "lime orange banana")); 

Et fonction qui retourne un tableau avec des allumettes et compteurs seront:

function count_between_words($text, $first, $second, $case_sensitive = false) 
{ 
    if(!preg_match_all('/('.$first.')((?:(?!\\1).)*?)'.$second.'/s' . ($case_sensitive ? "" : "i"), preg_replace("/\\s+/", " ", $text), $results, PREG_SET_ORDER)) 
     return array(); 

    $data = array(); 

    foreach($results as $result) 
    { 
     $result[2] = trim($result[2]); 
     $data[] = array("match" => $result[0], "words" => $result[2], "count" => count(split(" ", $result[2]))); 
    } 

    return $data; 
} 

$result = count_between_words($txt, "tükörfúrógép", "árvíztűrő"); 

echo "<pre>" . print_r($result, true) . "</pre>"; 

Le résultat sera:

Array 
(
    [0] => Array 
    (
     [match] => tükörfúrógép cherry árvíztűrő 
     [words] => cherry 
     [count] => 1 
    ) 

    [1] => Array 
    (
     [match] => tükörfúrógép cat orange lime cat árvíztűrő 
     [words] => cat orange lime cat 
     [count] => 4 
    ) 

    [2] => Array 
    (
     [match] => tükörfúrógép banana orange lime orange lime cat árvíztűrő 
     [words] => banana orange lime orange lime cat 
     [count] => 6 
    ) 
) 
+0

Merci William! C'est génial! Mais que se passe-t-il si vous inversez l'ordre des paramètres? Par exemple: $ resultat = count_between_words ($ txt, "árvíztűrő", "tükörfúrógép"); – turbod

+0

Rechercher l'inverse n'est pas une erreur de logique, c'est une recherche complètement différente. Pourquoi? : o – Wiliam

+0

+1 pour fournir une solution autonome. La regex a cependant besoin d'amélioration car elle fait des suppositions qui peuvent être fausses ou non (à savoir: '\ s *' et '[^,] +?') Et peut produire des faux négatifs à cause de cela. – Tomalak

Questions connexes