[php] Regexp: binnen èn buiten quotes

Pagina: 1
Acties:

  • 2
  • Registratie: November 2000
  • Laatst online: 31-03 13:52
Hallo,

Ik ben bezig een set statistieken scriptjes te maken, waarmee ik onder meer wil bekijken op welke zoekwoorden is gezocht door mensen die via searchengines op de site komen.

Ik kijk dus naar de referrer, het domein ervan en vervolgens of die in mijn database met domeinen van searchengines voorkomt. Ik heb bij iedere searchengine ook de variabele die ze gebruiken voor de zoektermen in de query_string (bijvoorbeeld "q", "search" of "search_for"). Op die manier heb ik dus de zoektermen waarop gezocht is.

Nu sla ik in principe de termen apart op, alleen wil ik meerdere termen die tussen aanhalingstekens staan als geheel opslaan. Oftewel
code:
1
naakte vrouwen met wapens en bier

wordt 6 entries, en
code:
1
"naakte vrouwen met wapens en bier"

wordt er 1.

Ik probeer dus iets te verzinnen om dit te matchen. Nu is het me op zich gelukt om het bovenstaande te bereiken op deze manier:
PHP:
1
<?if(preg_match_all("/\"(.+?)\"/", $searchstring, $multiTerms)) {  foreach($multiTerms[1] as $key => $value) {    $searchterms[] = $value;  }}else {  $searchterms = split(" |\\+|,", $searchstring);}?>

De zoektermen komen dus in Array $searchterms.

Maar, waar ik dus niet uit kom; wat nou als een gebruiker zowel termen tussen aanhalingstekens heeft staan als erbuiten, bijvoorbeeld:
code:
1
"naakte vrouwen" wapens bier

Ik dacht dus aan een regex te gebruiken als deze
PHP:
1
<?if(preg_match_all("/(.*?)\"(.+?)\"(.*?)/", $searchstring, $multiTerms)) {  ...}?>

maar ik weet dus niet precies of dit wel doet wat ik wil, en zo ja hoe ik het uit de array $multiTerms kan trekken.

Ik hoop dat mijn probleem een beetje duidelijk is.

Thx :)

Verwijderd

2: Wat nou als een gebruiker zowel termen tussen aanhalingstekens heeft staan als erbuiten, bijvoorbeeld:
code:
1
"naakte vrouwen" wapens bier
Het eerste wat in me op kwam (in Perl):
code:
1
2
3
4
5
6
7
8
9
10
11
use strict;
use warnings;

$_ = q/"naakte vrouwen" wapens bier/;

REGEXPARSING: {
    m/\G"([^"]+)"/gc && do { print "quoted term: $1\n"; redo; };
    m/\G(\w+)/gc     && do { print "single word: $1\n"; redo; };
    m/\G\s+/gc   && redo;
    m/\G[^\S\W"]+/gc && redo;
}

Output:
code:
1
2
3
quoted term: naakte vrouwen
single word: wapens
single word: bier

Helpt dat? :)

Verwijderd

Andere manier:
code:
1
2
3
4
$_ = q/"naakte vrouwen" wapens bier/;

print defined $1 ? "$1\n" : "$2\n"
    while / "([^"]+)" | (\S+) /gx;

Al weer Perl, maar gaat om het idee neem ik aan? :)

  • kvdveer
  • Registratie: November 2000
  • Laatst online: 06-11-2025

kvdveer

Z.O.Z.

probeer eens:
code:
1
2
3
4
5
6
7
/        // begin regexp
("?)        // eventueel een quote. backref 1
([a-z0-9 ]*?) // alle karakters, meervoudig, maar zo min mogelijk.
\1      // Backref 1, (Eventueel een quote)
          // spatie.
/        // einde regexp
i        // case insensitive

Zorg dat je zoektermen altijd eindigen op een spatie.

Localhost, sweet localhost


Verwijderd

kvdveer: [regex]
Dat krijg ik niet werkend...

Verwijderd

Op donderdag 28 maart 2002 15:29 schreef kvdveer het volgende:
probeer eens:
code:
1
2
3
4
5
6
7
/        // begin regexp
("?)        // eventueel een quote. backref 1
([a-z0-9 ]*?) // alle karakters, meervoudig, maar zo min mogelijk.
\1      // Backref 1, (Eventueel een quote)
          // spatie.
/        // einde regexp
i        // case insensitive

Zorg dat je zoektermen altijd eindigen op een spatie.
misschien handiger als je die spatie als \040 schrijft? :P

  • 2
  • Registratie: November 2000
  • Laatst online: 31-03 13:52
* 2 knars, moeluk moeluk

Héé Arien leef jij ook nog? :)
Op donderdag 28 maart 2002 15:07 schreef Arien
code:
1
2
3
4
5
6
7
8
9
10
11
use strict;
use warnings;

$_ = q/"naakte vrouwen" wapens bier/;

REGEXPARSING: {
    m/\G"([^"]+)"/gc && do { print "quoted term: $1\n"; redo; };
    m/\G(\w+)/gc     && do { print "single word: $1\n"; redo; };
    m/\G\s+/gc   && redo;
    m/\G[^\S\W"]+/gc && redo;
}
Ok ik probeer dus te kijken wat hier precies gebeurt om het om te zetten naar PHP, mijn perl kennis is niet zo rijkelijk dat ik dit meteen herken.

\G wil zeggen begin bij vorige match, wat in preg_match_all zit dus ..?

"([^"]+)" Matcht alles (dat geen kwoot is) tussen kwoots.

redo begint weer van voor af aan, zonder de laatste match opnieuw te doen - daardoor kun je match voor match de string doorlopen met verschillende mogelijk matches.

(\w+) oftewel [0-9a-zA-Z]+

m/\G\s+/gc Als er dan een spatie komt, zal er nog wel een zoekwoord komen, begin de loop dus weer opnieuw.

m/\G[^\S\W"]+/gc Als er een quote komt, zal er nog wel een zoekwoord komen, begin de loop dus weer opnieuw.

Klopt dit een beetje? Heb een beetje rond lopen zoeken, kende redo niet e.d. dus weet niet of het allemaal klopt. Ga ik nu proberen een equivalent te verzinnen in PHP.

  • tomato
  • Registratie: November 1999
  • Niet online
Arien: Het eerste wat in me op kwam (in Perl):
code:
1
perl
In PHP wordt dit heeeel anders (alleen al omdat \G en /c het waarschijnlijk niet doen) ;)
Arien: Andere manier:
code:
1
2
3
4
$_ = q/"naakte vrouwen" wapens bier/;

print defined $1 ? "$1\n" : "$2\n"
    while / "([^"]+)" | (\S+) /gx;
Daar dacht ik in eerste instantie ook aan.

'Hi' trouwens :*
2: Ga ik nu proberen een equivalent te verzinnen in PHP.
Ik zou dat met het tweede stukje code van Arien doen als ik jou was. Zoiets:
PHP:
1
<?if (preg_match_all('/ "([^"\\\\]*(?:\\\\.[^"\\\\]*)*)" | (\S+) /x', $s, $m, PREG_SET_ORDER)) {    $i = 0;    do {        print ( $m[$i][1] ? $m[$i][1]:$m[$i][2] )."\n";    } while ($m[$i++]);}?>

Als bonus heb ik het nog voor je mogelijk gemaakt om quotes te escapen :Y)

  • 2
  • Registratie: November 2000
  • Laatst online: 31-03 13:52
Op vrijdag 29 maart 2002 17:07 schreef tomato het volgende:
Ik zou dat met het tweede stukje code van Arien doen als ik jou was. Zoiets:
hé dat wilde ik dus doen :) Maar als ik het zo zie was ik er toch niet uit gekomen :P

Ben een beetje aan het proberen geweest om het te begrijpen, en het begint idd wel een beetje te dagen. Alleen merk ik dat hij op de een of andere manier ook lege strings geeft. Dus bij "vrouwen wapens" geeft hij 'vrouwen wapens' als match en ''.

Komt dit nou doordat hij ook een lege string match of komt het door de output van de do..while loop?

Trouwens, sorry voor mijn late reactie, was aant verhuizen.

  • tomato
  • Registratie: November 1999
  • Niet online
2: hé dat wilde ik dus doen :) Maar als ik het zo zie was ik er toch niet uit gekomen :P
Vast wel, het ziet er meer abracadabra uit dan het is ;)
Alleen merk ik dat hij op de een of andere manier ook lege strings geeft. Dus bij "vrouwen wapens" geeft hij 'vrouwen wapens' als match en ''.
Waarin komen die 'lege' matches dan voor? Zijn het niet precies die matches die er bij mijn voorbeeldje in de do-while loop uitgefilterd worden? Anders kan ik mij er niet zo heel veel bij voorstellen.
Komt dit nou doordat hij ook een lege string match of komt het door de output van de do..while loop?
Hij matcht geen lege string dus dat kan het niet zijn (een echte lege match is het dus niet).
Wbt de do-while loop, gebruik jij die ook als je dit probleem tegenkomt? Ik kijk in binnen die looop namelijk bij iedere match of er een quoted string of een unquoted string gematched is. Afhankelijk daarvan output ik het juiste deel van de match (het andere deel is dus leeg).

Je zou hem trouwens nog een beetje uit kunnen breiden, zodat ie ook werkt met enkele quotes (') ipv dubbele quotes (") ;)
Trouwens, sorry voor mijn late reactie, was aant verhuizen.
Geefnie, ik loop hier toch niet meer echt dagelijks rond ;)

  • 2
  • Registratie: November 2000
  • Laatst online: 31-03 13:52
Ik doe het in principe hetzelfde als jij, en als ik het precies hetzelfde doe krijg ik het ook.

Het is zo dat het niet uitmaakt hoeveel termen hij uitendeindelijk matcht, hij geeft er altijd maar 1 die leeg is. Vandaar dus dat ik vermoed dat die while loop gewoon 1 te ver gaat, maar ik zie niet in waarom :? Bijvoorbeeld dit:
PHP:
1
<?$s = '"Beter één" vogel "in de" hand "dan geen hand"';if (preg_match_all('/ "([^"\\\\]*(?:\\\\.[^"\\\\]*)*)" | (\S+) /x', $s, $m, PREG_SET_ORDER)) {  $i = 0;  print count($m) . "<BR>";  do{    print $m[$i]. " $i: ";    print($m[$i][1] ? $m[$i][1]:$m[$i][2] );    print  "|<BR>";  } while($m[$i++]);}?>

Geeft vreemdgenoeg dit als output:
code:
1
2
3
4
5
6
7
5
Array 0: Beter één|
Array 1: vogel|
Array 2: in de|
Array 3: hand|
Array 4: dan geen hand|
5: |

Oftewel, de laatste $m[i] is al geen array meer en toch doorloopt hij de loop nog een keer.
Op dinsdag 02 april 2002 12:09 schreef tomato het volgende:
Geefnie, ik loop hier toch niet meer echt dagelijks rond ;)
Hehe kwaliteit boven kwantiteit toch ;)

/edit:

Ja zo werkt hij wel:
PHP:
1
<?do{  print $m[$i]. " $i: ";  print($m[$i][1] ? $m[$i][1]:$m[$i][2] );  print  "|<BR>";  $i++;} while($m[$i]);?>

(met de $i++ binnen de haakjes dus)

  • tomato
  • Registratie: November 1999
  • Niet online
2: Vandaar dus dat ik vermoed dat die while loop gewoon 1 te ver gaat, maar ik zie niet in waarom :?
Ik zie hem al |:(
code:
1
$i++

Moet worden
code:
1
++$i

Want op dit moment kijkt hij eerst of $m[$i] nog bestaat en vervolgens verhoogt hij $i. Dat moet natuurlijk andersom :D
Hehe kwaliteit boven kwantiteit toch ;)
Altijd ;)

  • 2
  • Registratie: November 2000
  • Laatst online: 31-03 13:52
ahh!

Superbedankt (wederom)

:)
Pagina: 1