it-swarm.com.de

PHP: Bester Weg, um Text in Klammern zu extrahieren?

Was ist der beste/effizienteste Weg, um zwischen Klammern gesetzten Text zu extrahieren? Angenommen, ich wollte den String "text" so effizient wie möglich aus dem String "alles außer diesem (Text) ignorieren" erhalten.

Bisher habe ich mir am besten Folgendes ausgedacht:

$fullString = "ignore everything except this (text)";
$start = strpos('(', $fullString);
$end = strlen($fullString) - strpos(')', $fullString);

$shortString = substr($fullString, $start, $end);

Gibt es einen besseren Weg, dies zu tun? Ich weiß, dass die Verwendung von Regex im Allgemeinen weniger effizient ist, aber wenn ich die Anzahl der Funktionsaufrufe nicht reduzieren kann, ist dies möglicherweise der beste Ansatz. Gedanken?

68
Wilco

ich würde einfach einen Regex machen und es hinter mich bringen. Wenn Sie nicht genug Iterationen durchführen, um ein großes Leistungsproblem zu verursachen, ist das Programmieren einfacher (und Sie können verstehen, wenn Sie zurückblicken).

$text = 'ignore everything except this (text)';
preg_match('#\((.*?)\)#', $text, $match);
print $match[1];
120
Owen

Der von Ihnen eingegebene Code funktioniert also nicht: substr()'s Parameter sind $ string, $ start und $ length, und strpos()'s Parameter sind $haystack, $needle. Leicht modifiziert:

$ str = "Alles außer diesem (Text) ignorieren"; 
 $ start = strpos ($ str, '('); 
 $ end = strpos ($ str, ')', $ start + 1); 
 $ Length = $ end - $ start; 
 $ Result = substr ($ str, $ start + 1, $ length - 1);

Einige Feinheiten: Ich habe $start + 1 Im Parameter offset verwendet, um PHP out bei der Suche nach strpos() in der zweiten Klammer zu helfen; wir erhöhen $start Eins und reduzieren Sie $length, Um die Klammern von der Übereinstimmung auszuschließen.

Außerdem gibt es in diesem Code keine Fehlerprüfung: Sie sollten sicherstellen, dass $start Und $end Nicht === false sind, bevor Sie substr ausführen.

Bezüglich der Verwendung von strpos/substr Gegenüber Regex; In Bezug auf die Leistung schlägt dieser Code einen regulären Ausdruck zweifellos. Es ist allerdings etwas wortreicher. Ich esse und atme strpos/substr, Deshalb stört mich das nicht allzu sehr, aber jemand anderes mag die Kompaktheit eines Regex vorziehen.

12
Edward Z. Yang

Verwenden Sie einen regulären Ausdruck:

if( preg_match( '!\(([^\)]+)\)!', $text, $match ) )
    $text = $match[1];
8
Rob

Dies ist ein Beispielcode, mit dem der gesamte Text zwischen "[" und "]" extrahiert und in zwei separaten Arrays gespeichert wird (dh Text in Klammern in einem Array und Text außerhalb von Klammern in einem anderen Array).

   function extract_text($string)
   {
    $text_outside=array();
    $text_inside=array();
    $t="";
    for($i=0;$i<strlen($string);$i++)
    {
        if($string[$i]=='[')
        {
            $text_outside[]=$t;
            $t="";
            $t1="";
            $i++;
            while($string[$i]!=']')
            {
                $t1.=$string[$i];
                $i++;
            }
            $text_inside[] = $t1;

        }
        else {
            if($string[$i]!=']')
            $t.=$string[$i];
            else {
                continue;
            }

        }
    }
    if($t!="")
    $text_outside[]=$t;

    var_dump($text_outside);
    echo "\n\n";
    var_dump($text_inside);
  }

Ausgabe: extract_text ("Hallo, wie geht es dir?"); wird herstellen:

array(1) {
  [0]=>
  string(18) "hello how are you?"
}

array(0) {
}

extract_text ("Hallo [http://www.google.com/test.mp3], wie geht es dir?"); wird herstellen

array(2) {
  [0]=>
  string(6) "hello "
  [1]=>
  string(13) " how are you?"
}


array(1) {
  [0]=>
  string(30) "http://www.google.com/test.mp3"
}
3
Sachin Murali G

Diese Funktion kann nützlich sein.

    public static function getStringBetween($str,$from,$to, $withFromAndTo = false)
    {
       $sub = substr($str, strpos($str,$from)+strlen($from),strlen($str));
       if ($withFromAndTo)
         return $from . substr($sub,0, strrpos($sub,$to)) . $to;
       else
         return substr($sub,0, strrpos($sub,$to));
    }
    $inputString = "ignore everything except this (text)";
    $outputString = getStringBetween($inputString, '(', ')'));
    echo $outputString; 
    //output will be test

    $outputString = getStringBetween($inputString, '(', ')', true));
    echo $outputString; 
    //output will be (test)

strpos () => wird verwendet, um die Position des ersten Vorkommens in einem String zu ermitteln.

strrpos () => wird verwendet, um die Position des ersten Vorkommens in einem String zu ermitteln.

1
vijay
function getStringsBetween($str, $start='[', $end=']', $with_from_to=true){
$arr = [];
$last_pos = 0;
$last_pos = strpos($str, $start, $last_pos);
while ($last_pos !== false) {
    $t = strpos($str, $end, $last_pos);
    $arr[] = ($with_from_to ? $start : '').substr($str, $last_pos + 1, $t - $last_pos - 1).($with_from_to ? $end : '');
    $last_pos = strpos($str, $start, $last_pos+1);
}
return $arr; }

dies ist eine kleine Verbesserung gegenüber der vorherigen Antwort, die alle Muster in Array-Form zurückgibt:

getStringsBetween ('[T] his [] is [test] string [pattern]') gibt Folgendes zurück:

0
user628176

Die bereits geposteten regulären Ausdrücke - \((.*?)\) und \(([^\)]+)\) - geben die Zeichenfolgen innerste zwischen einer offenen und einer geschlossenen Klammer nicht zurück. Wenn ein String Text (abc(xyz 123) ist, dann beidereturn a (abc(xyz 123) Als Ganzes und nicht (xyz 123).

Das Muster, das Teilzeichenfolgen entspricht (verwenden Sie mit preg_match, Um die erste Zeichenfolge abzurufen, und preg_match_all, Um alle Vorkommen abzurufen), in Klammern ohne andere offene und geschlossene Klammern lautet, ob die Übereinstimmung Klammern enthalten soll:

\([^()]*\)

Oder Sie möchten Werte ohne Klammern erhalten:

\(([^()]*)\)        // get Group 1 values after a successful call to preg_match_all, see code below
\(\K[^()]*(?=\))    // this and the one below get the values without parentheses as whole matches 
(?<=\()[^()]*(?=\)) // less efficient, not recommended

Ersetzen Sie * Durch +, Wenn zwischen ( Und ) Mindestens ein Zeichen stehen muss.

Details :

  • \( - eine öffnende runde Klammer (muss maskiert werden, um eine wörtliche Klammer zu kennzeichnen, wie sie außerhalb einer Zeichenklasse verwendet wird)
  • [^()]* - null oder mehr andere Zeichen als ( und ) (beachten Sie diese ( und ) müssen nicht innerhalb einer Zeichenklasse als innerhalb davon maskiert werden, ( und ) können nicht zur Angabe einer Gruppierung verwendet werden und werden als wörtliche Klammern behandelt)
  • \) - eine schließende runde Klammer (muss maskiert werden, um eine wörtliche Klammer zu kennzeichnen, wie sie außerhalb einer Zeichenklasse verwendet wird).

Der Teil \(\K In einem alternativen regulären Ausdruck stimmt mit ( Überein und wird nicht im Übereinstimmungswert aufgeführt (mit dem Operator \K Zum Zurücksetzen von Übereinstimmungen). (?<=\() Ist ein positiver Lookbehind, bei dem ein ( Unmittelbar links von der aktuellen Position angezeigt werden muss, aber der ( Wird dem Übereinstimmungswert nicht hinzugefügt, da Lookbehind (Lookaround) Muster verbrauchen nicht. (?=\() Ist ein positiver Lookahead, für den ein ) - Zeichen unmittelbar rechts vom aktuellen Standort angezeigt werden muss.

PHP Code :

$fullString = 'ignore everything except this (text) and (that (text here))';
if (preg_match_all('~\(([^()]*)\)~', $fullString, $matches)) {
    print_r($matches[0]); // Get whole match values
    print_r($matches[1]); // Get Group 1 values
}

Ausgabe:

Array ( [0] => (text)  [1] => (text here) )
Array ( [0] => text    [1] => text here   )
0