PHP Zin: een string met geactiveerde eigennamen met een bekende woordenlijst?

Ik moet een reeks woorden doorzoeken tegen een woordenwoordenboek (txt-bestand) en elk woord dat niet gevonden is, kapitaliseren.

I'm trying to split the string into an array of words and check them against the unix /usr/dict/words dictionary. If a match is found for the word it gets lcfirst($word) if no match then ucfirst( $word )

Het woordenboek wordt geopend en in een array geplaatst met behulp van fgetcsv (ik heb ook geprobeerd om fgets te gebruiken en te exploderen aan het einde van de regel).

function wnd_title_case( $string ) {
$file = fopen( "/users/chris/sites/wp-dev/trunk/core/words.txt", "rb" );
while ( !feof( $file ) ) {
    $line_of_text = fgetcsv( $file );
     $exceptions = array( $line_of_text );
}


fclose( $file );
    $delimiters = array(" ", "-", "O'");
         foreach ( $delimiters as $delimiter ) {
            $words = explode( $delimiter, $string );
            $newwords = array();
                 foreach ($words as $word) {
                if ( in_array( strtoupper( $word ), $exceptions ) ) {
          //check exceptions list for any words that should be lower case
            $word = lcfirst( $word );
            } elseif ( !in_array( $word, $exceptions ) ) {
      //everything else capitalized
            $word = ucfirst( $word );
         }
       array_push( $newwords, $word );
       }
    $string = join( $delimiter, $newwords );
   }
        $string = ucfirst( $string );
   return $string;
}

Ik heb geverifieerd dat het bestand wordt geopend.

The desired output: Sentence case title string with proper nouns capitalized.
The current output: Title string with every word capitalized

Bewerk:

Met behulp van het antwoord van Jay hieronder kwam ik met een werkbare oplossing. Mijn eerste probleem was dat mijn woordenwoordenboek zowel hoofdletters als niet-hoofdletterwoorden bevatte, dus ik vond een eigen namenwoordenboek om te controleren of ik een regex-callback gebruikte. Het is niet perfect, maar krijgt het meestal goed.

function title_case( $string ) {
    $fp = @fopen( THEME_DIR. "/_/inc/propernames", "r" );  
        $exceptions = array();
        if ( $fp ) {

            while( !feof($fp) ) {
                    $buffer = fgets( $fp );
                array_push( $exceptions, trim($buffer) );
            }

        }

    fclose( $fp );

    $content = strtolower( $string );
    $pattern = '~\b' . implode ( '|', $exceptions ) . '\b~i';
    $content =  preg_replace_callback (  $pattern, 'regex_callback', $content  );
    $new_content =  $content;

    return ucfirst( $new_content );
}

    function regex_callback ( $data ) {
        if ( strlen( $data[0] )  > 3 )
        return ucfirst( strtolower( $data[0] ));
        else return ( $data[0] );

    }
1
exceptions wordt steeds overschreven, zodat deze alleen de laatste regel bevat. Niet zeker of dat het probleem (of alleen het probleem) is
toegevoegd de auteur Explosion Pills, de bron
Het is natuurlijk niet mogelijk om 100% nauwkeurigheid te bereiken met deze benadering; te veel eigennamen zijn ook gewone zelfstandige naamwoorden (Nick, Pools, ...).
toegevoegd de auteur Keith Thompson, de bron
Ik denk dat je meerdere problemen hebt en dat je je vraag over één probleem alleen moet stellen om betere antwoorden te krijgen. Isoleer uw problemen en herstel de ene na de andere.
toegevoegd de auteur hakre, de bron
In plaats van het exploderen van je string en looping voor elk woord, waarom niet gewoon een preg_replace of str_replace op de string als geheel doen?
toegevoegd de auteur Bart, de bron
/ usr/dict/words bevat enkele hoofd-voornaamwoorden, IIRC ...
toegevoegd de auteur Frank Farmer, de bron
Vraag verduidelijkt.
toegevoegd de auteur Chris_O, de bron

1 antwoord

De eenvoudigste manier om dit met regex te doen, is door het volgende te doen

  1. convert your text to all uppercase first letters $content = ucwords($original_content);
  2. Using your array of words in the dictionary, create a regex by imploding all your words with a pipe character |, and surrounding it with boundary markers and delimiters followed by the case insensitive flag, so you would end up with ~\bword1|word2|word3\b~i (obviously with your large list)
  3. create a function to lower the matched value using strtolower to be used with preg_replace_callback

Een voorbeeld van een werkende demo is dit

function regex_callback($data) {
    return strtolower($data[0]);
}

$original_content = 'hello my name is jay gilford';
$words = array('hello', 'my', 'name', 'is');

$content = ucwords($original_content);
$pattern = '~\b' . implode('|', $words) . '\b~i';

$content = preg_replace_callback($pattern, 'regex_callback', $content);

echo $content;

You could also optionally use strtolower to begin with on the content for consistency. The above code outputs hello my name is Jay Gilford

1
toegevoegd