obtener la primera letra de cada palabra

81

¿Cómo obtendría la primera letra de cada palabra para una cadena determinada?

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

Encontré el método javascript pero no estaba seguro de cómo convertirlo a php.

Grigor
fuente
1
¿Quiere saber cómo obtener la primera letra de su cadena, según cómo se formula su pregunta o cómo obtener la primera letra de cada palabra, según su ejemplo? Si el primero: $ resultado = $ cadena [0].
Anónimo
¿Estás seguro de que cada palabra está separada por un solo espacio? What__about__this__sentence?oWhat about.This sentence?
Mike B
Desarrolle francamente su propio script en PHP.
León
¿Cuáles son los caracteres que calificarían como separadores? ¿Espacio, guión, guión bajo, etc.?
Surreal Dreams
1
explote la cadena en los espacios en blanco y luego recorra la matriz de resultados y, dado que cada una es una cadena, puede usar $ string [0] para obtener el primer carácter y luego simplemente concatenarlos.
slash197

Respuestas:

136

explode()en los espacios, luego usa la []notación para acceder a las cadenas resultantes como matrices:

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

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

Si tiene la expectativa de que varios espacios pueden separar palabras, cambie a preg_split()

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

O si, -,_por ejemplo, caracteres distintos a los espacios en blanco delimitan palabras ( ), utilice preg_split()también:

// Delimit by multiple spaces, hyphen, underscore, comma
$words = preg_split("/[\s,_-]+/", "Community College District");
Michael Berkowski
fuente
14
Al grano:preg_match_all("/[A-Z]/", ucwords(strtolower($string)), $matches);
dmmd
46

La mejor forma de lograr esto es con expresiones regulares.

Analicemos lo que quiere de una manera lógica: quiere que todos los caracteres de la cadena estén al principio de una palabra. La mejor forma de identificar esos caracteres es buscar aquellos que estén precedidos por espacios en blanco.

Entonces comenzamos con una búsqueda hacia atrás para ese carácter de espacio, seguido de cualquier carácter:

/(?<=\s)./

Esto encontrará cualquier carácter precedido por un espacio. Pero, el primer carácter de la cadena es un carácter de la cadena que desea extraer. Y como es el primer carácter de la cadena, no puede ir precedido de un espacio. Así que queremos hacer coincidir cualquier cosa precedida por un espacio o el primer carácter de la cadena, por lo que agregamos una aserción de inicio de sujeto :

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

Ahora nos estamos acercando. Pero, ¿y si la cadena contiene bloques de varios espacios? ¿Qué pasa si contiene un espacio seguido de un carácter de puntuación? Probablemente no queremos hacer coincidir ninguno de esos, en grasa probablemente solo queremos hacer coincidir las letras. Podemos hacer eso con una clase de personaje [a-zA-Z] . Y podemos hacer que una expresión no distinga entre mayúsculas y minúsculas usando el i modificador .

Entonces terminamos con:

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

Pero, ¿cómo usamos esto en PHP? Bueno, queremos hacer coincidir todas las apariciones de la expresión regular dentro de la cadena, así que usamos (lo adivinó) preg_match_all():

$string = "Progress in Veterinary Science";

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

Ahora tenemos todos los personajes que queríamos extraer. Para construir la cadena de resultados que muestra, debemos unirlos nuevamente :

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

... y debemos asegurarnos de que estén en mayúsculas :

$result = strtoupper($result);

Y eso es realmente todo lo que hay que hacer.

Verlo funcionando

DaveRandom
fuente
1
Si quisiera, también podría usar en (?<=\b)lugar de (?<=\s|^), esto le permitiría capturar las letras iniciales de las palabras separadas por guiones, puntos, etc. (básicamente, caracteres "que no son palabras", aquellos que no coincidirían con \ w o \ W), pero también podría terminar capturando cosas que no desea.
Leigh
¡Tu solución ayudó mucho! Gracias !
yathrakaaran
1
Definitivamente esta debería ser la respuesta. Extremadamente detallado y funciona perfectamente, ¡gracias!
Steve Bauman
Esto me ayudó, pero ¿qué pasa con el caso de $ string = "Progress in Veterinary Science (Brower County)"; la 'B' se deja caer. Cualquier pensamiento
Ken
17

Suponiendo que todas las palabras están divididas por espacios, esta es una solución adecuada:

$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
fuente
Creo que $ word [0] es más rápido que substr ($ word, 0,1) así que ¿por qué usas substr ($ word, 0,1)?
Sir l33tname
1
Simplemente no confío mucho en las cadenas como matrices. He tenido algunos errores emergentes en el pasado
casraf
Editar: TL; DR: solo viejos hábitos
casraf
2
@LeonardChallis No sé, si Chen Asraf se estaba refiriendo a este tipo de errores, pero usar substr($word,0,1)(o en realidad - mb_substr($word, 0, 1, 'utf-8')) es una necesidad absoluta, si está operando en cadenas de varios bytes. El uso de simple $word[0]cortará la mitad de un carácter de varios bytes y le dará una inicial incorrecta: algún símbolo extraño en lugar de la letra real. Si se refiere a esta situación como un error, ¡ahí tiene su respuesta! :]
trejder
Cualquier método o forma de ignorar palabras como (en, el, de, a ...) y obtener la salida como "PVS" en lugar de "PIVS"
Fenil Shah
9

Hay muchas exploderespuestas. Creo que usar la strtokfunción es una solución mucho más elegante y eficiente en memoria:

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);

Aquí hay una función más robusta y útil, que admite caracteres UTF8 y la opción de usar solo las palabras en mayúscula:

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
fuente
No estoy de acuerdo, su código es masivo en comparación con los métodos de explosión.
Dale
3
@Dale Bueno, eso nos dice más sobre ti que sobre mi código; la estética es una mala forma de evaluar el código. Usar explodepara resolver este problema es lo que se llamaría una solución ingenua . Es como usar el algoritmo de clasificación de burbujas solo porque es fácil de implementar.
Sverri M. Olsen
@MAssiveAmountsOfCode No estoy de acuerdo ¿por qué hacer algo en 13 líneas de código que se pueda lograr en 1 foreach(explode(' ', $string) as $word) echo $word[0];? Más fácil de entender de un vistazo y no es una pérdida de tiempo.
Dale
Además, ¿qué tiene de ingenuo dividir una cadena de palabras separadas por un espacio, por un espacio? Creo que su comentario nos dice que es un codificador pomposo que no está abierto a revisiones de código.
Dale
3
@Dale No quise insultarlo ni parecer pomposo. Es ingenuo porque la explosión de una cadena crea una matriz, donde no se necesita. Tokenizar la cadena es más elegante porque está pasando por la cadena original, que requiere menos memoria. No estoy diciendo que usar explodesea incorrecto (hace el trabajo), pero que hay una palabra más elegante para resolver el problema. Y no estoy usando la palabra "elegante" de manera estética, la estoy usando de manera técnica.
Sverri M. Olsen
7

La respuesta de Michael Berkowski (y otros), simplificada a una línea y funcionando correctamente con caracteres de varios bytes (es decir, haciendo abreviaturas / iniciales de una cadena no latina):

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

Usar mb_substr($word, 0, 1, 'utf-8'), en lugar de $word[0]parece ser obligatorio, si está trabajando en cadenas y caracteres no latinos, de múltiples bytes, es decir, cuando usa cadenas codificadas en UTF-8.

trejder
fuente
5
$temp = explode(' ', $string);
$result = '';
foreach($temp as $t)
    $result .= $t[0];
Ascherer
fuente
5

Me gusta esto

preg_match_all('#(?<=\s|\b)\pL#u', $String, $Result);
echo '<pre>' . print_r($Result, 1) . '</pre>';
Winston
fuente
Agradable. Tengo un problema con la primera letra de mi código. ¿Qué carácter indica la primera letra? <=?
Narek
1
+1 para \pL. Sin embargo, ¿podrías agregar una pequeña explicación? Prefiero enseñarle a pescar a un hombre en lugar de simplemente darle uno ;-)
DaveRandom
@Narek (? <=) Esta es una mirada positiva detrás de este detalle
Winston
@DaveRandom aquí datail sobre estos caracteres
Winston
@Winston Lo sé (aunque tomé el enfoque KISS en mi respuesta), quise decir más para el OP ;-) pero gracias de todos modos :-)
DaveRandom
4

Como explicaron otros, la forma clásica consiste en iterar sobre cada palabra de su cadena inicial, reducir la palabra a su primera letra y combinar esas primeras letras juntas.

Aquí hay un método auxiliar que combina los diferentes pasos.

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

NB: esto devolverá una cadena vacía en caso de que la cadena dada esté vacía.

getInitials('Community College District')

cadena 'CCD' (longitud = 3)

getInitials()

cadena '' (longitud = 0)

getInitials('Lorem ipsum dolor sic amet')

cadena 'Lidsa' (longitud = 5)

Por supuesto, puede agregar filtros a la función de devolución de llamada de array_reduce(), por ejemplo, strtoupper()si prefiere solo las iniciales en mayúscula, por ejemplo.

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

// would output IaaS
billyonecan
fuente
3

Algo que he preparado.

/**
 * 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;
}

fuente
2
function acronym( $string = '' ) {
    $words = explode(' ', $string);
    if ( ! $words ) {
        return false;
    }
    $result = '';
    foreach ( $words as $word ) $result .= $word[0];
    return strtoupper( $result );
}
smassey
fuente
1

Creo que tienes que explotar y unirte a ellos de nuevo .....

<?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
fuente
1

Usando la base Prateeks, aquí hay un ejemplo simple con explicaciones

//  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
fuente
Esta es mi primera solución publicada en este sitio. HTH!
Rob Stocki
1

Si hay más espacios entre dos letras en la cadena de entrada, intente esto.

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

Alternativa del mismo código

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
fuente
1

Aquí hay una función que le da las iniciales de un nombre y si las iniciales son solo 1 letra, entonces devuelve las 2 primeras letras del nombre.

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
fuente
1

¿Por qué no usar la función str_word_count para esto?

  1. obtener cada palabra como una fila en una matriz
  2. reducir esa matriz a la primera letra

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

Spir
fuente
0

Prueba esto-

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

foreach($strs as $str)
  echo $str[0];
Prateek Shukla
fuente
0

Algo como esto debería funcionar:

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

En el caso de que haga esto en cadenas grandes (o incluso directamente desde el archivo) explode() no es la mejor manera de hacerlo. Imagínese cuánta memoria se desperdiciará si tiene que dividir una cadena de 2 MB en memoria.

Con un poco más de codificación y (asumiendo PHP >= 5.0) puede implementar fácilmente la Iteratorclase de PHP que hará exactamente esto. Esto estará cerca del generador en Python y, en pocas palabras, aquí está el código:

/**
 * 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);
    }
}

Y si lo usa en una cadena un poco más desafiante:

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

Obtendrá el resultado esperado:

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

Por lo tanto, puede usarlo fácilmente $i[0]para buscar la primera letra. Probablemente pueda ver que esta es una solución más efectiva que dividir la cadena completa en la memoria (siempre use solo la menor cantidad de memoria posible). También puede modificar fácilmente esta solución para que funcione con la lectura continua de archivos, etc.

Vyktor
fuente
0
<?php $arr = explode(" ",$String);

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

?>

En primer lugar, exploto la cadena por espacios y luego hago una subestación del primer carácter.

http://php.net/substr

http://php.net/explode

Robert
fuente
0

Prueba esto

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
fuente
0

Me gusta Reg Expression sobre cualquier otro método de extracción de cadenas, pero si no está familiarizado con Reg Ex, escuche que es un método que usa la explode()función PHP:

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

Obviamente, el código anterior solo funcionará con un nombre que contenga dos palabras.

Matt Jameson
fuente
0

Esta respuesta https://stackoverflow.com/a/33080232/1046909 pero con soporte de cadenas multibyte:

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
fuente
0

Puede usar esa función según la respuesta aceptada de @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;
}

El parámetro $ length determina cuántos caracteres desea mostrar

USO:

$acronym = buildAcronym("Hello World", 2);
Couranos
fuente