In PHP, how would one take a string and separate the words into an array? Is there a way to split them by the spaces in the string? Also, how would you check if a word in an array starts with a character? The idea would be to have a textbox with come normal words and a hashtag. The PHP script would maybe underline or change the color of the hashtag when you submit the form. It would basically underline any word that started with a hash. Sorry if this doesn't make any sense.
To convert a string to an array, use PHP's explode function:
$array = explode(' ', $string);
To examine whether each word begins with a certain character, you can use strpos in a loop:
// Pick a letter
$char = 'a';
foreach ($array as $word) {
if (strpos($word, $char) === 0) {
// Echo out what you want
echo "$word contains $char\r\n";
// Halt loop if necessary:
break;
}
}
Related
I have a piece of code that I'm struggling with. I'm still on my first steps so it's entirely possible that some silly mistake is causing this.
I want to turn each first character of each word into uppercase, but for some reason it is not working and I cannot get it figured out.
$split = explode(" ",$string);
foreach ($split as $word) {
if (ord($word[0]) >= 97 & ord($word[0]) <= 122){
$word[0] = chr(ord($word[0]) - 32);
}}
return $string;
}
You should handle this a little differently.
Let's create our split first:
$words = explode(' ', $words_string);
Now let's loop through these words and remember their index by using the $key param.
foreach($words as $index => $word) { //So we remember the key in the array using $k => $v
$words[$index] = ucfirst($word); //This will uppercase the first letter.
}
The reason why it's not working is explained in the question i've linked.
However in your case the solution is much more simple. You can just use ucwords() function or mb_convert_case() with MB_CASE_TITLE if you work with multibyte strings.
PHP provides in-built function that help you convert every word's first character to uppercase of the string without exploding and iterating through.
ucwords( $string );
EDIT: Let us include a sample to help you out what would be the output:
echo ucwords("Hi this is just a simple test of converting each word's first charater to uppercase!");
will return
Hi This Is Just A Simple Test Of Converting Each Word's First Charater To Uppercase!
I have a group of letters, for example :
$word='estroaroint';
that can be arranged to be words like :
- store
- train
- restoration
- ...etc
They can be found in my file list 'dictionary.txt'.
A letter only can only be used once.
How to write a php script able to perform that?
I would try to manage it with this function: strpbrk() http://php.net/manual/en/function.strpbrk.php
It isn't really possible to do that in one step with a regex. However, it is possible to do it in two steps:
the first step find all the words in the dictionary that only contains the letters.
the second step filter words where letters are repeated.
Example (only for ascii range):
$pattern = '~\b[' . $word . ']{1,' . strlen($word) . '}+\b~';
if (preg_match_all($pattern, $dictionary, $m)) {
$chars = count_chars ($word, 1);
$result = array_filter($m[0], function ($i) use ($chars) {
foreach (count_chars($i, 1) as $k=>$v) {
if ($v > $chars[$k]) return false;
}
return true;
});
print_r($result);
}
PHP links: array_filter - count_chars
Note: to extend this script to multibyte characters, you need to write your own function mb_count_chars (since this function doesn't exist) that splits a multibyte string (you can use for example mb_substr, mb_strlen and a loop, or preg_split with ~(?=.)~u and the PREG_SPLIT_NO_EMPTY option). You need to add the u modifier to the regex pattern too and to change strlen to its multybyte equivalent.
I am trying to use certain words in a array called keywords, which will be used to be replaced in a string by "as".
for($i = 0; $i<sizeof($this->keywords[$this->lang]); $i++)
{
$word = $this->keywords[$this->lang][$i];
$a = preg_replace("/\b$word\b/i", "as",$this->code);
}
It works with if I replace the variable $word with something like /\bhello\b/i, which then would replace all hello words with "as".
Is the approach am using even possible?
Before to be a pattern, it's a double quoted string, so variables will be replaced, it's not the problem.
The problem is that you use a loop to change several words and you store the result in $a:
the first iteration, all the occurences of the first word in $this->code are replaced and the new string is stored in $a.
but the next iteration doesn't reuse $a as third parameter to replace the next word, but always the original string $this->code
Result: after the for loop $a contains the original string but with only the occurences of the last word replaced with as.
When you want to replace several words with the same string, a way consists to build an alternation: word1|word2|word3.... It can easily be done with implode:
$alternation = implode('|', $this->keywords[$this->lang]);
$pattern = '~\b(?:' . $alternation . ')\b~i';
$result = preg_replace($pattern, 'as', $this->code);
So, when you do that, the string is parsed only once and all the words are replaced in one shot.
If you have a lot of words and a very long string:
Testing a long alternation has a significant cost. Even if the pattern starts with \b that highly reduces the possible positions for a match, your pattern will have hard time to succeed and more to fail.
Only in this particular case, you can use this another way:
First you define a placeholder (a character or a small string that can't be in your string, lets say §) that will be inserted in each positions of word boundaries.
$temp = preg_replace('~\b~', '§', $this->code);
Then you change all the keywords like this §word1§, §word2§ ... and you build an associative array where all values are the replacement string:
$trans = [];
foreach ($this->keywords[$this->lang] as $word) {
$trans['§' . $word . '§'] = 'as';
}
Once you have do that you add an empty string with the placeholder as key. You can now use the fast strtr function to perform the replacement:
$trans['§'] = '';
$result = strtr($temp, $trans);
The only limitation of this technic is that it is case-sensitive.
it will work if you keep it like bellow:
$a = preg_replace("/\b".$word."\b/i", "as",$this->code);
Consider the following string
$input = "string with {LABELS} between brackets {HERE} and {HERE}";
I want to temporarily remove all labels (= whatever is between curly braces) so that an operation can be performed on the rest of the string:
$string = "string with between brackets and";
For arguments sake, the operation is concatenate every word that starts with 'b' with the word 'yes'.
function operate($string) {
$words = explode(' ', $string);
foreach ($words as $word) {
$output[] = (strpos($word, 0, 1) == 'b') ? "yes$word" : $word;
}
return implode(' ', $output);
}
The output of this function would be
"string with yesbetween yesbrackets and"
Now I want to insert the temporarily deleted labels back into place:
"string with {LABELS} yesbetween yesbrackets {HERE} and {HERE}"
My question is: how can I accomplish this? Important: I am not able to alter operate(), so the solution should contain a wrapper function around operate() or something. I have been thinking about this for quite a while now, but am confused as to how to do this. Could you help me out?
Edit: it would be too much to put the actual operate() in this post. It will not really add value (except make the post longer). There is not much difference between the output of operate() here and the real one. I will be able to translate any ideas from here, to the real-world situation :-)
The answer to this depends on wether or not you are able to understand operate(), even if you can't change it.
If you have absolutely no insight into operate(), your problem is simply unsolvable: To reinsert your labels you need one of
Their offset or relative position (You can't know them, if you don't know operate())
A marker for their place (You can't have them, if you don't know how operate() will work on them)
If you have at least some insight into operate(), this becomes something between solvable and easy:
If operate($a . $b)==operate($a) . operate($b), then you just split your original input by the labels, run the non-label parts through operate(), but obviously not the labels, then reassemble
If operate() is guaranteed to let a placeholder string, that itself is guaranteed to be not part of the normal input ("\0" and friends come to mind) alone, then you extract your labels in order, replace them by the placeholder, run the result through operate() and later replace the placeholder by your saved labels (in order)
Edit
After reading your comments, here are some lines of code
$input = "string with {LABELS} between brackets {HERE} and {HERE}";
//Extract labels and replace with \0
$tmp=preg_split('/(\{.*?\})/',$input,-1,PREG_SPLIT_DELIM_CAPTURE);
$labels=array();
$txt=array();
$islabel=false;
foreach ($tmp as $t) {
if ($islabel) $labels[]=$t;
else $txt[]=$t;
$islabel=!$islabel;
}
$txt=implode("\0",$txt);
//Run through operate()
$txt=operate($txt);
//Reasssemble
$txt=explode("\0",$txt);
$result='';
foreach ($txt as $t)
$result.=$t.array_shift($labels);
echo $result;
Here's what I would do as a first attempt. Split your string into single words, then feed them into operate() one by one, depending on whether the word is 'braced' or not.
$input = "string with {LABELS} between brackets {HERE} and {HERE}";
$inputArray = explode(' ',$input);
foreach($inputArray as $key => $value) {
if(!preg_match('/^{.*}$/',$value)) {
$inputArray[$key] = operate($value);
}
}
$output = implode(' ',$inputArray);
I have a string like abcdefg123hijklm. I also have an array which contains several strings like [456, 123, 789].
I want to check if the number in the middle of abcdefg123hijklm exists in the array.
How can I do that? I guess in_array() won't work.
So you want to check if any substring of that particular string (lets call it $searchstring) is in the array?
If so you will need to iterate over the array and check for the substring:
foreach($array as $string)
{
if(strpos($searchstring, $string) !== false)
{
echo 'yes its in here';
break;
}
}
See: http://php.net/manual/en/function.strpos.php
If you want to check if a particular part of the String is in the array you will need to use substr() to separate that part of the string and then use in_array() to find it.
http://php.net/manual/en/function.substr.php
Another option would be to use regular expressions and implode, like so:
if (preg_match('/'.implode('|', $array).'/', $searchstring, $matches))
echo("Yes, the string '{$matches[0]}' was found in the search string.");
else
echo("None of the strings in the array were found in the search string.");
It's a bit less code, and I would expect it to be more efficient for large search strings or arrays, since the search string will only have to be parsed once, rather than once for every element of the array. (Although you do add the overhead of the implode.)
The one downside is that it doesn't return the array index of the matching string, so the loop might be a better option if you need that. However, you could also find it with the code above followed by
$match_index = array_search($matches[0], $array);
Edit: Note that this assumes you know your strings aren't going to contain regular expression special characters. For purely alphanumeric strings like your examples that will be true, but if you're going to have more complex strings you would have to escape them first. In that case the other solution using a loop would probably be simpler.
You can do it reversely. Assume your string is $string and array is $array.
foreach ($array as $value)
{
// strpos can return 0 as a first matched position, 0 == false but !== false
if (strpos($string, $value) !== false)
{
echo 'Matched value is ' . $value;
}
}
Use this to get your numbers
$re = "/(\d+)/";
$str = "abcdefg123hijklm";
preg_match($re, $str, $matches);
and ( 123 can be $matches[1] from above ):
preg_grep('/123/', $array);
http://www.php.net/manual/en/function.preg-grep.php