Uzyskaj pierwszą literę każdego słowa w ciągu

81

Jak uzyskać pierwszą literę każdego słowa dla danego ciągu?

$string = "Community College District";
$result = "CCD";

Znalazłem metodę javascript, ale nie byłem pewien, jak przekonwertować ją na php.

Grigor
źródło
1
Czy chcesz wiedzieć, jak uzyskać pierwszą literę swojego ciągu, zgodnie z tym, jak sformułowane jest twoje pytanie lub jak uzyskać pierwszą literę każdego słowa, jak na twoim przykładzie? Jeśli pierwszy: $ wynik = $ ciąg [0].
Anonimowy
Jesteś pewien, że każde słowo jest oddzielone pojedynczą spacją? What__about__this__sentence?lubWhat about.This sentence?
Mike B
Szczerze, stwórz własny skrypt w PHP.
Lion,
Jakie znaki kwalifikują się jako separatory? Spacja, kreska, podkreślenie itp.?
Surreal Dreams,
1
rozbij ciąg na białe spacje, a następnie zapętlaj tablicę wyników, a ponieważ każdy z nich jest łańcuchem, możesz użyć $ string [0], aby uzyskać pierwszy znak, a następnie po prostu je połączyć.
slash197

Odpowiedzi:

136

explode()na spacjach, używasz []notacji, aby uzyskać dostęp do wynikowych ciągów jako tablic:

$words = explode(" ", "Community College District");
$acronym = "";

foreach ($words as $w) {
  $acronym .= $w[0];
}

Jeśli spodziewasz się, że wiele spacji może oddzielać słowa, przełącz się na preg_split()

$words = preg_split("/\s+/", "Community College District");

Lub jeśli na przykład znaki inne niż białe znaki ograniczają słowa ( -,_), użyj preg_split()również:

// Delimit by multiple spaces, hyphen, underscore, comma
$words = preg_split("/[\s,_-]+/", "Community College District");
Michaela Berkowskiego
źródło
14
Do preg_match_all("/[A-Z]/", ucwords(strtolower($string)), $matches);
rzeczy
46

Najlepszym sposobem, aby to osiągnąć, są wyrażenia regularne.

Pozwala podzielić to, co chcesz w logiczny sposób: chcesz, aby każdy znak z ciągu znajdował się na początku słowa. Najlepszym sposobem na zidentyfikowanie tych znaków jest wyszukanie tych znaków, które są poprzedzone białymi znakami.

Zaczynamy więc od spojrzenia wstecz na ten znak spacji, po którym następuje dowolny znak:

/(?<=\s)./

Spowoduje to znalezienie dowolnego znaku poprzedzonego spacją. Ale - pierwszy znak w ciągu to znak w ciągu, który chcesz wyodrębnić. A ponieważ jest to pierwszy znak w ciągu, nie może być poprzedzony spacją. Chcemy więc dopasować wszystko, co jest poprzedzone spacją lub pierwszym znakiem w ciągu, więc dodajemy potwierdzenie początku tematu :

/(?<=\s|^)./

Teraz jesteśmy coraz bliżej. Ale co, jeśli ciąg zawiera bloki z wieloma spacjami? A jeśli zawiera spację, po której następuje znak interpunkcyjny? Prawdopodobnie nie chcemy dopasować żadnego z nich, w tłuszczu prawdopodobnie chcemy dopasować tylko litery. Możemy to zrobić z klasą postaci [a-zA-Z] . I możemy sprawić, że wyrażenia nie będą rozróżniać wielkości liter za pomocą i modyfikatora .

Tak więc otrzymujemy:

/(?<=\s|^)[a-z]/i

Ale jak właściwie używamy tego w PHP? Cóż, chcemy dopasować wszystkie wystąpienia wyrażenia regularnego w ciągu, więc używamy (zgadłeś) preg_match_all():

$string = "Progress in Veterinary Science";

$expr = '/(?<=\s|^)[a-z]/i';
preg_match_all($expr, $string, $matches);

Teraz mamy wszystkie postacie, które chcieliśmy wyodrębnić. Aby skonstruować ciąg wynikowy, który pokazujesz, musimy połączyć je ponownie :

$result = implode('', $matches[0]);

... i musimy upewnić się, że wszystkiepisane wielkimi literami :

$result = strtoupper($result);

I to naprawdę wszystko.

Zobacz, jak działa

DaveRandom
źródło
1
Jeśli chcesz, możesz również użyć (?<=\b)zamiast (?<=\s|^), pozwoli to na przechwycenie początkowych liter słów oddzielonych myślnikami, kropkami itp. (W zasadzie znaki „inne niż słowo”, te, które nie pasują do \ w lub \ W), ale może też skończyć się przechwyceniem rzeczy, których nie chcesz.
Leigh,
Twoje rozwiązanie bardzo pomogło! Dziękuję Ci !
yathrakaaran
1
To zdecydowanie powinna być odpowiedź. Niezwykle szczegółowe i działa idealnie, dzięki!
Steve Bauman
Pomogło mi to, ale co z przypadkiem $ string = "Progress in Veterinary Science (Brower County)"; „B” jest odrzucane. Wszelkie przemyślenia
Ken
17

Zakładając, że wszystkie słowa są podzielone spacjami, jest to odpowiednie rozwiązanie:

$string = "Progress in Veterinary Science";

function initials($str) {
    $ret = '';
    foreach (explode(' ', $str) as $word)
        $ret .= strtoupper($word[0]);
    return $ret;
}

echo initials($string); // would output "PIVS"
casraf
źródło
Myślę, że $ word [0] jest szybsze niż substr ($ word, 0,1), więc dlaczego używasz substr ($ word, 0,1)?
Sir l33tname
1
Po prostu nie ufam łańcuchom jako tablicom. W przeszłości
pojawiały się
Edycja: TL; DR: tylko stare nawyki
casraf
2
@LeonardChallis Nie wiem, czy Chen Asraf odnosił się do tego rodzaju błędów, ale użycie substr($word,0,1)(a właściwie - mb_substr($word, 0, 1, 'utf-8')) jest absolutną koniecznością, jeśli pracujesz na ciągach wielobajtowych. Użycie simple $word[0]spowoduje obcięcie wielobajtowej połowy znaku i podanie nieprawidłowego inicjału - jakiś dziwny symbol zamiast rzeczywistej litery. Jeśli określisz tę sytuację jako błąd, masz swoją odpowiedź! :]
trejder
Dowolna metoda lub sposób ignorowania słów takich jak (in, the, of, a ...) i uzyskiwania wyniku jako „PVS” zamiast „PIVS”
Fenil Shah
9

Odpowiedzi jest wiele explode. Myślę, że użycie tej strtokfunkcji jest dużo bardziej eleganckim i oszczędzającym pamięć rozwiązaniem:

function createAcronym($string) {
    $output = null;
    $token  = strtok($string, ' ');
    while ($token !== false) {
        $output .= $token[0];
        $token = strtok(' ');
    }
    return $output;
}
$string = 'Progress in Veterinary Science';
echo createAcronym($string, false);

Oto bardziej niezawodna i użyteczna funkcja, która obsługuje znaki UTF8 i opcję używania tylko słów pisanych wielką literą:

function createAcronym($string, $onlyCapitals = false) {
    $output = null;
    $token  = strtok($string, ' ');
    while ($token !== false) {
        $character = mb_substr($token, 0, 1);
        if ($onlyCapitals and mb_strtoupper($character) !== $character) {
            $token = strtok(' ');
            continue;
        }
        $output .= $character;
        $token = strtok(' ');
    }
    return $output;
}
$string = 'Leiðari í Kliniskum Útbúgvingum';
echo createAcronym($string);
Sverri M. Olsen
źródło
Nie zgadzam się, twój kod jest ogromny w porównaniu z metodami eksplodującymi.
Dale
3
@Dale Cóż, to mówi nam więcej o tobie niż o moim kodzie - estetyka to kiepski sposób oceny kodu. Stosując explodesię do rozwiązania tego problemu jest to, co można nazwać naiwnością rozwiązanie . To tak, jakby używać algorytmu sortowania bąbelkowego tylko dlatego, że jest łatwy do wdrożenia.
Sverri M. Olsen
@MAssiveAmountsOfCode Nie zgadzam się, po co robić coś w 13 liniach kodu, co można osiągnąć w 1 foreach(explode(' ', $string) as $word) echo $word[0];? Łatwiejsze do zrozumienia na pierwszy rzut oka i bez straty czasu.
Dale
A co jest naiwnego w dzieleniu ciągu słów oddzielonych spacją, spacją? Myślę, że twoja uwaga mówi nam, że jesteś pompatycznym programistą, który nie jest otwarty na recenzje kodu.
Dale
3
@Dale Nie chciałem cię obrazić ani wyglądać na pompatycznego. Jest to naiwne, ponieważ rozbicie łańcucha tworzy tablicę, w której nie jest ona potrzebna. Tokenizacja ciągu jest bardziej elegancka, ponieważ przechodzisz przez oryginalny ciąg, który wymaga mniej pamięci. Nie mówię, że używanie explodejest złe (wykonuje swoją pracę), ale że istnieje bardziej eleganckie określenie rozwiązania problemu. I nie używam słowa „elegancki” w sposób estetyczny, używam go w sposób techniczny.
Sverri M. Olsen
8

Odpowiedź Michała Berkowskiego (i innych), uproszczona do jednej linii i działająca poprawnie na znakach wielobajtowych (tj. Tworzenie skrótu / inicjałów z niełacińskiego ciągu):

foreach(explode(' ', $words) as $word) $acronym .= mb_substr($word, 0, 1, 'utf-8');

Używanie mb_substr($word, 0, 1, 'utf-8'), zamiast $word[0]wydaje się być obowiązkowe, jeśli pracujesz z niełacińskimi, wielobajtowymi łańcuchami i znakami, np. Używając łańcuchów zakodowanych w UTF-8.

trejder
źródło
5
$temp = explode(' ', $string);
$result = '';
foreach($temp as $t)
    $result .= $t[0];
Ascherer
źródło
5

Lubię to

preg_match_all('#(?<=\s|\b)\pL#u', $String, $Result);
echo '<pre>' . print_r($Result, 1) . '</pre>';
Winston
źródło
Miły. Mam problem z pierwszą literą w moim kodzie. Jaki znak wskazuje pierwszą literę? <=?
Narek
1
+1 dla \pL. Czy mógłbyś jednak dodać małe wyjaśnienie? Wolę nauczyć człowieka łowić ryby, niż po prostu go dać ;-)
DaveRandom
@Narek (? <=) To jest Positive Lookbehind this detail
Winston
@DaveRandom tutaj datail o tym znaku
Winston,
@Winston ja wiem (chociaż ja wziąłem podejście kiss w mojej odpowiedzi), miałem na myśli bardziej dla PO ;-) ale i tak dzięki :-)
DaveRandom
5

Jak wyjaśnili inni, klasyczny sposób polega na iteracji po każdym słowie początkowego ciągu, zredukowaniu słowa do jego pierwszej litery i połączeniu tych pierwszych liter razem.

Oto metoda pomocnicza łącząca różne kroki.

/**
 * @return string
 */
function getInitials($string = null) {
    return array_reduce(
        explode(' ', $string),
        function ($initials, $word) {
            return sprintf('%s%s', $initials, substr($word, 0, 1));
        },
        ''
    );
}

Uwaga: to zwróci pusty ciąg w przypadku, gdy podany ciąg jest pusty.

getInitials('Community College District')

ciąg „CCD” (długość = 3)

getInitials()

string '' (długość = 0)

getInitials('Lorem ipsum dolor sic amet')

ciąg „Lidsa” (długość = 5)

Oczywiście możesz dodać filtry do funkcji wywołania zwrotnego array_reduce(), na przykład strtoupper()jeśli wolisz tylko inicjały pisane wielkimi literami.

Flo Schild
źródło
3
$str = 'I am a String!';
echo implode('', array_map(function($v) { return $v[0]; }, explode(' ', $str)));

// would output IaaS
billyonecan
źródło
3

Coś, co ugotowałem.

/**
 * Return the first letter of each word in uppercase - if it's too long.
 *
 * @param string $str
 * @param int $max
 * @param string $acronym
 * @return string
 */
function str_acronym($str, $max = 12, $acronym = '')
{
    if (strlen($str) <= $max) return $str;

    $words = explode(' ', $str);

    foreach ($words as $word)
    {
        $acronym .= strtoupper(substr($word, 0, 1));
    }

    return $acronym;
}

źródło
2
function acronym( $string = '' ) {
    $words = explode(' ', $string);
    if ( ! $words ) {
        return false;
    }
    $result = '';
    foreach ( $words as $word ) $result .= $word[0];
    return strtoupper( $result );
}
smassey
źródło
2

Dlaczego nie użyć do tego funkcji str_word_count ?

  1. pobierz każde słowo jako wiersz w tablicy
  2. zmniejszyć tę tablicę do pierwszej litery

    $ acronym = array_reduce (str_word_count ("Community College District", 1), function ($ res, $ w) {return $ res. $ w [0];});

Spir
źródło
1

Myślę, że musisz eksplodować i ponownie do nich dołączyć .....

<?php
$string  = "Progress in Veterinary Science";
$pieces = explode(" ", $string);
$str="";
foreach($pieces as $piece)
{
    $str.=$piece[0];
}    
echo $str; /// it will result into  "PiVS"
?>
Ravindra Shekhawat
źródło
1

Korzystając z fundacji Prateeks, oto prosty przykład z wyjaśnieniami

//  initialize variables
$string = 'Capitalize Each First Word In A String';
$myCapitalizedString = '';

//  here's the code
$strs=explode(" ",$string);    
foreach($strs as $str) {
  $myCapitalizedString .= $str[0]; 
}

//  output
echo $myCapitalizedString;  // prints 'CEFWIAS'
Rob Stocki
źródło
To jest moje pierwsze rozwiązanie opublikowane na tej stronie. HTH!
Rob Stocki
1

Jeśli jest więcej spacji między dwiema literami w ciągu wejściowym, spróbuj tego.

function first_letter($str)
{
    $arr2 = array_filter(array_map('trim',explode(' ', $str)));
    $result='';
    foreach($arr2 as $v)
    {
        $result.=$v[0];
    }
    return $result;
}

$str="    Let's   try   with    more   spaces       for  fun .   ";

echo first_letter($str);

Demo1

Alternatywa tego samego kodu

function first_letter($str)
{
    return implode('', array_map(function($v) { return $v[0]; },array_filter(array_map('trim',explode(' ', $str)))));;
}

$str="    Let's   try   with    more   spaces       for  fun .   ";

echo first_letter($str);

Demo2

Durgesh Tiwari
źródło
1

Oto funkcja, która pobiera inicjały imienia i jeśli inicjały mają tylko jedną literę, zwraca pierwsze 2 litery imienia.

function getNameInitials($name) {

    preg_match_all('#(?<=\s|\b)\pL#u', $name, $res);
    $initials = implode('', $res[0]);

    if (strlen($initials) < 2) {
        $initials = strtoupper(substr($name, 0, 2));
    }

    return strtoupper($initials);
}
Salam
źródło
0

Spróbuj tego-

$strs=explode(" ",$string);

foreach($strs as $str)
  echo $str[0];
Prateek Shukla
źródło
0

Coś takiego powinno załatwić sprawę:

$string = 'Some words in a string';
$words = explode(' ', $string); // array of word
foreach($words as $word){
    echo $word[0]; // first letter
}
Marshall
źródło
0

W przypadku, gdy będziesz to robić na dużych łańcuchach (lub nawet bezpośrednio z pliku), explode()nie jest to najlepszy sposób. Wyobraź sobie, ile pamięci zostanie zmarnowane, jeśli będziesz musiał podzielić łańcuch o wielkości 2 MB na pamięć.

Przy odrobinie więcej kodowania i (zakładając PHP >= 5.0) możesz łatwo zaimplementować Iteratorklasę PHP, która zrobi dokładnie to. Będzie to zbliżone do generatora w Pythonie i krótko mówiąc, oto kod:

/**
 * Class for CONTINOUS reading of words from string.
*/
class WordsIterator implements Iterator {
    private $pos = 0;
    private $str = '';
    private $index = 0;
    private $current = null;

    // Regexp explained:
    // ([^\\w]*?) - Eat everything non-word before actual word characters
    //              Mostly used only if string beings with non-word char
    // ([\\w]+)   - Word
    // ([^\\w]+?|$) - Trailing thrash
    private $re = '~([^\\w]*?)([\\w]+)([^\\w]+?|$)~imsS';

    // Primary initialize string
    public function __construct($str) {
        $this->str = $str;
    }

    // Restart indexing
    function rewind() {
        $this->pos = 0;
        $this->index = 0;
        $this->current = null;
    }

    // Fetches current word
    function current() {
        return $this->current;
    }

    // Return id of word you are currently at (you can use offset too)
    function key() {
        return $this->index;
    }

    // Here's where the magic is done
    function next() {
        if( $this->pos < 0){
            return;
        }

        $match = array();
        ++$this->index;

        // If we can't find any another piece that matches... Set pos to -1
        // and stop function
        if( !preg_match( $this->re, $this->str, $match, 0, $this->pos)){
            $this->current = null;
            $this->pos = -1;
            return;
        }

        // Skip what we have read now
        $this->current = $match[2];
        $this->pos += strlen( $match[1]) + strlen( $match[2]) + strlen($match[3]);

        // We're trying to iterate past string
        if( $this->pos >= strlen($this->str)){
            $this->pos = -1;
        }

    }

    // Okay, we're done? :)
    function valid() {
        return ($this->pos > -1);
    }
}

A jeśli użyjesz go na nieco trudniejszym łańcuchu:

$a = new WordsIterator("Progress in Veterinary Science. And, make it !more! interesting!\nWith new line.");
foreach( $a as $i){
    echo $i;
    echo "\n";
}

Czy uzyskasz oczekiwany wynik:

Progress
in
Veterinary
Science
And
make
it
more
interesting
With
new
line

Możesz więc łatwo $i[0]pobrać pierwszą literę, prawdopodobnie widzisz, że jest to bardziej efektywne rozwiązanie niż dzielenie całego ciągu do pamięci (zawsze używaj tylko jak najmniejszej ilości pamięci). Możesz również łatwo zmodyfikować to rozwiązanie, aby działało z ciągłym czytaniem plików itp.

Vyktor
źródło
0
<?php $arr = explode(" ",$String);

foreach($arr as $s)
{
   echo substr($s,0,1);
}

?>

najpierw rozbijam ciąg o spacje, a następnie podciągam pierwszy znak.

http://php.net/substr

http://php.net/explode

Robert
źródło
0

Spróbuj tego

function initials($string) {
        if(!(empty($string))) {
            if(strpos($string, " ")) {
                $string = explode(" ", $string);
                $count = count($string);
                $new_string = '';
                for($i = 0; $i < $count; $i++) {
                $first_letter = substr(ucwords($string[$i]), 0, 1);
                $new_string .= $first_letter;
            }
            return $new_string;
            } else {
                $first_letter = substr(ucwords($string), 0, 1);
                $string = $first_letter;
                return $string;
            }
        } else {
            return "empty string!";
        }
    }
    echo initials('Thomas Edison');
San
źródło
0

Lubię Reg Expression zamiast innych metod ekstrakcji ciągów, ale jeśli nie jesteś zaznajomiony z Reg Ex, to usłyszysz metodę wykorzystującą funkcję explode()PHP:

$string = "David Beckham";
$string_split = explode(" ", $string);
$inititals = $string_split[0][0] . $string_split[1][0];
echo $inititals;

Oczywiście powyższy kod będzie działał tylko dla nazwy zawierającej dwa słowa.

Matt Jameson
źródło
0

Ta odpowiedź https://stackoverflow.com/a/33080232/1046909, ale z obsługą ciągów wielobajtowych:

if (!function_exists('str_acronym')) {
    function str_acronym(string $str, int $min = -1, string $prefix = null): string
    {
        if (mb_strlen($str) <= $min) {
            return $str;
        };

        $words = explode(' ', $str);

        $acronym = strval($prefix);

        foreach ($words as $word) {
            if ($word = trim($word)) {
                $acronym .= mb_strtoupper(mb_substr($word, 0, 1));
            }
        }

        return $acronym;
    }
}
MingalevME
źródło
0

Możesz użyć tej funkcji na podstawie zaakceptowanej odpowiedzi od @Michael Berkowski

function buildAcronym($string, $length = 1) {
    $words = explode(" ", $string);
    $acronym = "";
    $length = (self::is_empty($string) || $length <= 0 ? 1 : $length);

    foreach ($words as $i => $w) {
        $i += 1;
        if($i <= $length) {
            $acronym .= $w[0];
        }
    }

    return $acronym;
}

Parametr $ length określa, ile znaków chcesz wyświetlić

STOSOWANIE:

$acronym = buildAcronym("Hello World", 2);
Couranos
źródło