it-swarm.com.de

CamelCase Word mit php preg_match (regulärer Ausdruck) in Wörter aufteilen

Wie würde ich das Wort teilen?

oneTwoThreeFour

in ein Array, damit ich bekommen kann:

one Two Three Four

mit preg_match?

Ich habe es müde, aber es gibt nur das ganze Wort

$words = preg_match("/[a-zA-Z]*(?:[a-z][a-zA-Z]*[A-Z]|[A-Z][a-zA-Z]*[a-z])[a-zA-Z]*\b/", $string, $matches)`;
59
Good-bye

Sie können auch preg_match_all verwenden als:

preg_match_all('/((?:^|[A-Z])[a-z]+)/',$str,$matches);

Erläuterung:

(        - Start of capturing parenthesis.
 (?:     - Start of non-capturing parenthesis.
  ^      - Start anchor.
  |      - Alternation.
  [A-Z]  - Any one capital letter.
 )       - End of non-capturing parenthesis.
 [a-z]+  - one ore more lowercase letter.
)        - End of capturing parenthesis.
74
codaddict

Sie können preg_split verwenden als:

$arr = preg_split('/(?=[A-Z])/',$str);

Sieh es

Ich teile die Eingabezeichenfolge vor dem Großbuchstaben auf. Der verwendete Ausdruck (?=[A-Z]) stimmt mit dem Punkt vor einem Großbuchstaben überein.

65
codaddict

Ich weiß, dass dies eine alte Frage mit einer akzeptierten Antwort ist, aber IMHO gibt es eine bessere Lösung:

<?php // test.php Rev:20140412_0800
$ccWord = 'NewNASAModule';
$re = '/(?#! splitCamelCase Rev:20140412)
    # Split camelCase "words". Two global alternatives. Either g1of2:
      (?<=[a-z])      # Position is after a lowercase,
      (?=[A-Z])       # and before an uppercase letter.
    | (?<=[A-Z])      # Or g2of2; Position is after uppercase,
      (?=[A-Z][a-z])  # and before upper-then-lower case.
    /x';
$a = preg_split($re, $ccWord);
$count = count($a);
for ($i = 0; $i < $count; ++$i) {
    printf("Word %d of %d = \"%s\"\n",
        $i + 1, $count, $a[$i]);
}
?>

Beachten Sie, dass dieser Regex (wie die '/(?=[A-Z])/'-Lösung von codaddict - die wie ein Zauber für wohlgeformte camelCase-Wörter wirkt) nur eine position innerhalb des Strings entspricht und keinerlei Text verbraucht. Diese Lösung hat den zusätzlichen Vorteil, dass sie auch für nicht so gut geformte Pseudo-Camelcase-Wörter wie StartsWithCap und: hasConsecutiveCAPS korrekt funktioniert.

Eingang:

oneTwoThreeFour
StartsWithCap
hasConsecutiveCAPS
NewNASAModule 

Ausgabe:

Word 1 of 4 = "one"
Word 2 of 4 = "Two"
Word 3 of 4 = "Three"
Word 4 of 4 = "Four" 

Word 1 of 3 = "Starts"
Word 2 of 3 = "With"
Word 3 of 3 = "Cap" 

Word 1 of 3 = "has"
Word 2 of 3 = "Consecutive"
Word 3 of 3 = "CAPS" 

Word 1 of 3 = "New"
Word 2 of 3 = "NASA"
Word 3 of 3 = "Module" 

Bearbeitet: 2014-04-12: Geänderte Regex-, Skript- und Testdaten, um den Fall "NewNASAModule" richtig zu teilen (als Antwort auf den Kommentar von rr).

49
ridgerunner

Eine funktionalisierte Version der Antwort von @ ridgerunner.

/**
 * Converts camelCase string to have spaces between each.
 * @param $camelCaseString
 * @return string
 */
function fromCamelCase($camelCaseString) {
        $re = '/(?<=[a-z])(?=[A-Z])/x';
        $a = preg_split($re, $camelCaseString);
        return join($a, " " );
}
11
blak3r

Die Antwort von ridgerunner funktioniert zwar großartig, scheint aber nicht mit Großbuchstaben zu funktionieren, die in der Satzmitte erscheinen. Ich benutze folgendes und es scheint damit klar zu gehen:

function splitCamelCase($input)
{
    return preg_split(
        '/(^[^A-Z]+|[A-Z][^A-Z]+)/',
        $input,
        -1, /* no limit for replacement count */
        PREG_SPLIT_NO_EMPTY /*don't return empty elements*/
            | PREG_SPLIT_DELIM_CAPTURE /*don't strip anything from output array*/
    );
}

Einige Testfälle:

assert(splitCamelCase('lowHigh') == ['low', 'High']);
assert(splitCamelCase('WarriorPrincess') == ['Warrior', 'Princess']);
assert(splitCamelCase('SupportSEELE') == ['Support', 'SEELE']);
assert(splitCamelCase('LaunchFLEIAModule') == ['Launch', 'FLEIA', 'Module']);
assert(splitCamelCase('anotherNASATrip') == ['another', 'NASA', 'Trip']);
10
rr-
$string = preg_replace( '/([a-z0-9])([A-Z])/', "$1 $2", $string );

Der Trick ist ein wiederholbares Muster von $ 1 $ 2 $ 1 $ 2 oder niedriger UPPERlower UPPERlower etc .... Zum Beispiel HelloWorld = $ 1 entspricht "hallo", "2" entspricht "W" und "1" entspricht "orld" Sie erhalten $ 1 $ 2 $ 1 oder "Hallo Welt", entspricht HelloWorld als $ 2 $ 1 $ 2 $ 1 oder wieder "Hello World". Dann können Sie das erste Word in Großbuchstaben schreiben oder auf dem Feld explodieren oder ein _ oder ein anderes Zeichen verwenden, um sie voneinander zu trennen.

Kurz und einfach.

5
ArtisticPheonix

Ich habe den Code von cooler Ridgerunner (oben) genommen und eine Funktion erstellt:

echo deliciousCamelcase('NewNASAModule');

function deliciousCamelcase($str)
{
    $formattedStr = '';
    $re = '/
          (?<=[a-z])
          (?=[A-Z])
        | (?<=[A-Z])
          (?=[A-Z][a-z])
        /x';
    $a = preg_split($re, $str);
    $formattedStr = implode(' ', $a);
    return $formattedStr;
}

Dies wird zurückgegeben: New NASA Module

2
Jarrod

Bei der Ermittlung des besten Musters für Ihr Projekt müssen Sie die folgenden Musterfaktoren berücksichtigen:

  1. Genauigkeit (Robustheit) - ob das Muster in allen Fällen korrekt und einigermaßen zukunftssicher ist
  2. Effizienz - Das Muster sollte direkt und bewusst sein und unnötige Arbeit vermeiden
  3. Kürze - Das Muster sollte geeignete Techniken verwenden, um unnötige Zeichenlängen zu vermeiden
  4. Lesbarkeit - Das Muster sollte so einfach wie möglich gehalten werden

Die oben genannten Faktoren liegen zufällig auch in der hierarchischen Reihenfolge, die danach strebt, zu gehorchen. Mit anderen Worten, es macht für mich wenig Sinn, 2, 3 oder 4 zu priorisieren, wenn 1 die Anforderungen nicht ganz erfüllt. Die Lesbarkeit steht für mich am Ende der Liste, da ich in den meisten Fällen der Syntax folgen kann.

Erfassungsgruppen und Lookarounds wirken sich häufig auf die Mustereffizienz aus. Die Wahrheit ist, es sei denn, Sie führen diesen regulären Ausdruck mit Tausenden von Eingabezeichenfolgen aus, besteht keine Notwendigkeit, über die Effizienz zu streiten. Es ist vielleicht wichtiger, sich auf die Musterlesbarkeit zu konzentrieren, die mit der Musterkürze in Verbindung gebracht werden kann.

Einige der folgenden Muster erfordern eine zusätzliche Behandlung/Kennzeichnung durch ihre preg_ -Funktion, aber hier sind einige Mustervergleiche, die auf der Beispieleingabe des OP basieren:

preg_split() patterns:

  • /^[^A-Z]+\K|[A-Z][^A-Z]+\K/ (21 Schritte)
  • /(^[^A-Z]+|[A-Z][^A-Z]+)/ (26 Schritte)
  • /[^A-Z]+\K(?=[A-Z])/ (43 Schritte)
  • /(?=[A-Z])/ (50 Schritte)
  • /(?=[A-Z]+)/ (50 Schritte)
  • /([a-z]{1})[A-Z]{1}/ (53 Schritte)
  • /([a-z0-9])([A-Z])/ (68 Schritte)
  • /(?<=[a-z])(?=[A-Z])/x (94 Schritte) ... für den Datensatz ist die x unbrauchbar.
  • /(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/ (134 Schritte)

preg_match_all() patterns:

  • /[A-Z]?[a-z]+/ (14 Schritte)
  • /((?:^|[A-Z])[a-z]+)/ (35 Schritte)

Ich werde darauf hinweisen, dass es einen subtilen Unterschied zwischen der Ausgabe von preg_match_all() und preg_split() gibt. preg_match_all() gibt ein zweidimensionales Array aus, mit anderen Worten, alle Übereinstimmungen mit der vollständigen Zeichenfolge befinden sich im Unterarray [0]. Wenn eine Erfassungsgruppe verwendet wird, befinden sich diese Teilzeichenfolgen im Unterfeld [1]. Andererseits gibt preg_split() nur ein eindimensionales Array aus und bietet daher einen weniger aufgeblähten und direkteren Pfad zur gewünschten Ausgabe.

Einige der Muster sind nicht ausreichend, wenn es sich um camelCase-Zeichenfolgen handelt, die eine ALLCAPS/acronym-Teilzeichenfolge enthalten. Wenn dies ein Randfall ist, der in Ihrem Projekt möglich ist, ist es logisch, nur Muster zu berücksichtigen, die diese Fälle korrekt behandeln. Ich werde keine TitleCase-Eingabezeichenfolgen testen, da dies zu weit von der Frage entfernt ist.

Neue, erweiterte Batterie mit Teststrings:

oneTwoThreeFour
hasConsecutiveCAPS
newNASAModule
USAIsGreatAgain 

Geeignete preg_split()-Muster:

  • /[a-z]+\K|(?=[A-Z][a-z]+)/ (149 Schritte) * Ich musste [a-z] verwenden, damit die Demo richtig zählt
  • /(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/ (547 Schritte)

Geeignet preg_match_all() muster:

  • /[A-Z]?[a-z]+|[A-Z]+(?=[A-Z][a-z]|$)/ (75 Schritte)

Schließlich meine Empfehlungen auf der Grundlage meiner Musterprinzipien/Faktorhierarchie. Außerdem empfehle ich preg_split() gegenüber preg_match_all() (trotz der Muster mit weniger Schritten), um die gewünschte Ausgabestruktur direkt zu erreichen. (natürlich, wähle was du willst)

Code: ( Demo )

$noAcronyms = 'oneTwoThreeFour';
var_export(preg_split('~^[^A-Z]+\K|[A-Z][^A-Z]+\K~', $noAcronyms, 0, PREG_SPLIT_NO_EMPTY));
echo "\n---\n";
var_export(preg_match_all('~[A-Z]?[^A-Z]+~', $noAcronyms, $out) ? $out[0] : []);

Code: ( Demo )

$withAcronyms = 'newNASAModule';
var_export(preg_split('~[^A-Z]+\K|(?=[A-Z][^A-Z]+)~', $withAcronyms, 0, PREG_SPLIT_NO_EMPTY));
echo "\n---\n";
var_export(preg_match_all('~[A-Z]?[^A-Z]+|[A-Z]+(?=[A-Z][^A-Z]|$)~', $withAcronyms, $out) ? $out[0] : []);
1
mickmackusa

Eine andere Option ist das Abgleichen von /[A-Z]?[a-z]+/. Wenn Sie wissen, dass Ihre Eingabe das richtige Format hat, sollte es gut funktionieren.

[A-Z]? würde mit einem Großbuchstaben (oder nichts) übereinstimmen. [a-z]+ würde dann bis zum nächsten Buchstaben mit allen folgenden Kleinbuchstaben übereinstimmen.

Arbeitsbeispiel: https://regex101.com/r/kNZfEI/1

1
Kobi

Volle Funktion basierend auf @codaddict Antwort:

function splitCamelCase($str) {
    $splitCamelArray = preg_split('/(?=[A-Z])/', $str);

    return ucwords(implode($splitCamelArray, ' '));
}
0
guizo

Vielleicht kann Ihnen meine Frage helfen. Ich habe gestern dasselbe gefragt, aber über Java

Zeichenketten in Großbuchstaben aufteilen

0
pringlesinn

Sie können bei einem "Gleiten" von Kleinbuchstaben zu Großbuchstaben aufteilen, also:

$parts = preg_split('/([a-z]{1})[A-Z]{1}/', $string, -1, PREG_SPLIT_DELIM_CAPTURE);        
//PREG_SPLIT_DELIM_CAPTURE to also return bracketed things
var_dump($parts);

Ärgerlicherweise müssen Sie dann die Wörter aus jedem entsprechenden Elementpaar in $ parts neu erstellen

Hoffe das hilft

0
Daniel Rhodes

Zunächst einmal danke ich dir für dein Muster, es hat sehr geholfen!

Ich brauchte eine Lösung, die funktioniert, wenn eine Präposition 'a' existiert:

z.B. thisIsACamelcaseSentence.

Ich habe die Lösung in einem zweistufigen preg_match gefunden und eine Funktion mit einigen Optionen erstellt: 

/*
 * input: 'thisIsACamelCaseSentence' output: 'This Is A Camel Case Sentence'
 * options $case: 'allUppercase'[default] >> 'This Is A Camel Case Sentence'
 *                'allLowerCase'          >> 'this is a camel case sentence'
 *                'firstUpperCase'        >> 'This is a camel case sentence'
 * @return: string
 */

function camelCaseToWords($string, $case = null){
    isset($case) ? $case = $case : $case = 'allUpperCase';

    // Find first occurances of two capitals
    preg_match_all('/((?:^|[A-Z])[A-Z]{1})/',$string, $twoCapitals);

    // Split them with the 'zzzzzz' string. e.g. 'AZ' turns into 'AzzzzzzZ'
    foreach($twoCapitals[0] as $match){
        $firstCapital = $match[0];
        $lastCapital = $match[1];
        $temp = $firstCapital.'zzzzzz'.$lastCapital;
        $string = str_replace($match, $temp, $string);  
    }

    // Now split words
    preg_match_all('/((?:^|[A-Z])[a-z]+)/', $string, $words);

    $output = "";
    $i = 0;
    foreach($words[0] as $Word){

            switch($case){
                case 'allUpperCase':
                $Word = ucfirst($Word);
                break;

                case 'allLowerCase': 
                $Word = strtolower($Word);
                break;

                case 'firstUpperCase':
                ($i == 0) ? $Word = ucfirst($Word) : $Word = strtolower($Word);
                break;                  
            }

            // remove te 'zzzzzz' from a Word if it has
            $Word = str_replace('zzzzzz','', $Word);    
            $output .= $Word." ";
            $i++;
    }
    return $output; 
}

Fühlen Sie sich frei, es zu benutzen, und falls es eine "einfachere" Möglichkeit gibt, dies in einem Schritt zu tun, kommentieren Sie bitte!

0
joronimo