I need make something that includes a function that uses explode to create an array. I have seen several examples, but near the end I really get confused! Is there a simple readable way for this? (//comments?)
Take for instance a piece of text:
"This is a simple text I just created".
The output should look like this:
This is a
simple text I
just created
So the explode should split the text into lines of 3 words each.
$text = "This is a simple text I just created";
$text_array = explode(" ", $text);
$chunks = array_chunk($text_array, 3);
foreach ($chunks as $chunk) {
$line = $impode(" ", $chunk);
echo $line;
echo "<br>";
}
Try this is what you need:
<?php
$text = "This is a simple text I just created";
$text_array = explode(' ', $text);
$i = 1; // I made change here :)
foreach($text_array as $key => $text){
if(ceil(($key + 1) / 3) != $i) { echo "<br/>"; $i = ceil(($key + 1) / 3); }
echo $text.' ';
}
?>
Result:
This is a
simple text I
just created
Use substr() function link
Example:
<?php
$rest = substr("abcdef", -1); // returns "f"
$rest = substr("abcdef", -2); // returns "ef"
$rest = substr("abcdef", -3, 1); // returns "d"
?>
In your case:
<?php
$rest = substr("This is a simple text I just created", 0, 15); //This will return first 15 characters from your string/text
echo $rest; // This is a simpl
?>
explode just splits the string at a specified character. There's nothing more to it.
explode(',', 'Text,goes,here');
This splits the string whenever it meets a , and returns an array.
to split by a space character
explode(' ', 'Text goes here');
This splits only by a space character, not all whitespace. Preg_split would be easier to split by any whitespace
So something like...
function doLines($string, $nl){
// Break into 'words'
$bits = explode(' ', $string);
$output = '';
$counter=0;
// Go word by word...
foreach($bits as $bit){
//Add the word to the output...
$output .= $bit.' ';
//If it's 3 words...
if($counter==2){
// Remove the trailing space
$output = substr($output, 0, strlen($output)-1);
//Add the separator character...
$output .=$nl;
//Reset Counter
$counter=0;
}
}
//Remove final trailing space
$output = substr($output, 0, strlen($output)-1);
return $output;
}
Then all you have to is:
echo doLines("This is a simple text I just created", "\n");
or
echo doLines("This is a simple text I just created", "<br />");
..depending if you just want new lines or if you want HTML output.
Related
for (my $j = 0; $j <100000; $j++){
my $outcome = rand();
for (my $k = 0; $k < #cum_sum; $k++){
if ($cum_sum[$k] >= $outcome){
if ($keys[$k] =~ m/\"|\/|\<|\>|\\|\`|\~|\#|\#|\$|\%|\^|\*|[0-9]/) {
print $out "";
}
if ($keys[$k] =~ m/\s/){
print $out " ";
}
elsif ($keys[$k] =~ m/\&/){
print $out " and ";
}
elsif ($keys[$k] =~ m/\!/){
print $out "! ";
}
elsif ($keys[$k] =~ m/\:/){
print $out ": ";
}
elsif ($keys[$k] =~ m/\'/){
print $out "' ";
}
elsif ($keys[$k] =~ m/\./){
print $out ". ";
}
elsif ($keys[$k] =~ m/\;/){
print $out "; ";
}
elsif ($keys[$k] =~ m/\?/){
print $out "? ";
}
elsif ($keys[$k] =~ m/\,/){
print $out ", ";
}
else {
print $out "$keys[$k]";
}
last;
}
}
# print "$outcome\n";
}
I mostly need help with simplifying the long chain of elsif statements I have.
The logic in the outer for loops works.
#keys is an array of two character (digrams) strings.
I am trying to make the elsif statements more efficient by comparing the digrams from #key to an array of the punctuation marks #punctuation = qw(! : " ' ; ? , .)
Then, if the digram does contain one of the punctuation marks in the punctuation array, the digram gets changed to "punctuation_mark " e.g. "a!" -> "! "
The end result would be that I do not use regexes for any of #punctuation.
However, I am not sure on how to implement this change.
Thank you!
In order to simplify your code, it may have sense to use the Tie::RegexpHash CPAN module. The main idea is build a hash with regexpr as keys, so you easily find the related values by matching:
use Tie::RegexpHash;
my $rehash = Tie::RegexpHash->new();
$rehash->add( qr/\s/, " " );
$rehash->add( qr/\&/, " and " );
#...
my $value = $rehash->match( "&" ); # $value <-- " and "
Use alternation, just like in the first regex, but capture the match and use $1 to replace the word
my $re_punct = join '|', map { quotemeta } qw(& ! : ' . ; ? ,); #'
for my $j (0..99_999) {
my $outcome = rand();
for my $k (0..$#cum_sum) {
...
if ($keys[$k] =~ /($re_punct)/) {
if ($1 eq '&') { $keys[$k] = " and " }
else { $keys[$k] = "$1 " }
}
...
}
}
Comments
quotemeta escapes by \ all "ASCII non-"word" characters"
syntax: $#ary is the index of the last element in #ary, just right for looping over array index
for my $i ($beg .. $end) is much clearer than the equivalent C-style for loop†
The presented logic leaves a question: what if both characters are punctuation?
Note on your idea to do it "By Comparing With Array"
You could use List::MoreUtils::first_value, for instance. It would go like
use List::MoreUtils qw(first_value);
my #punc = map { quotemeta } qw(& ! : ' . ; ? ,); #'
foreach my $word (#words) {
if (my $match = first_value { $word =~ /$_/ } #punct) {
$word = $match;
}
}
The first_value (or firstval) returns the first element of #punct for which the block returns true, and undef if none do. The $word aliases the currently processed element of #words and changing it changes the array element; so you get your replacement.
However, you still have to deal with regex and escape (at least some of) punctuation. Thus I see no advantage in going to this trouble; the "straight-up" regex is far clearer in this case.
† Even compiled languages evolve this way. The C++11 introduced the range-based for loop
for (auto var: container) ... // (really, const auto&), or auto&, or auto&&
and a standard reference linked above says
Used as a more readable equivalent to the traditional for loop [...]
In Perl this is how things are done; just use it.
So, looking at it you have two cases:
One where you replace a set of values, with 'the value and a space'. And another where you replace with something different.
So how about creating a lookup table for each, and processing just two regexes:
#!/usr/bin/env perl.
use strict;
use warnings;
use Data::Dumper;
my %replace = (
'"' => "",
'/' => "",
'&' => " and ",
);
my #add_space = ( ',', '?', ';', '.', "'", ':', '!' );
my $search = join ( "|", map { quotemeta } keys %replace );
$search = qr/($search)/;
my $add_space_after = join "|", map {quotemeta} #add_space;
$add_space_after = qr/($add_space_after)/;
while ( <DATA> ) {
s/\s/ /g;
s/$search/$replace{$1}/;
s/$add_space_after/$1 /;
print;
}
__DATA__
Work:Work
cookies&milk;wordhere
why?are;you/so "sad"
This gives us what you want I think, and - hopefully - keeps the code pretty conscise.
Of importance is the quotemeta function here, because it ensures your metachars are escaped before regexing them.
Note - the only one of your examples this doesn't handle is the \s to " ". But that's IMO probably best to write separately for clarity, as obviously youc can't quotemeta it.
I need to get the words before and after "globe" in the string text "hello,planet,globe,city,country".
So, I was trying to get the word before " ,globe," until the previous comma, meaning it should return "planet".
I also need to return the next word "city".
If the word is at the beginning of the string,
previous word should be entered as "no word".
If the word is at the end of the string,
next word should be entered as "no word".
How do i do it? Thanks in advance. Is this preg_match the best choice?
$word = "fsdfs";
$text = "hello,planet,globe,city,country";
preg_match('/[$word]+/', $text, $match);
//the above sentence is wrong but wanted to emphasise that $word needs to mentioned in it
print_r($match);
^(.*?),?\s*globe\K(.*)$
You can use this and grab the capture or group.See demo.
$re = "/^(.*?),?\\s*globe\\K(.*)$/m";
$str = "hello,planet,globe,city,country\nglobe,city,country\nhello,planet,globe";
preg_match_all($re, $str, $matches);
preg_match is probably the wrong choice for this.
You have a few choices, you could use str_replace to simply remove 'globe' from the string, then what you have left is what you want.
You could also use explode to turn the string into an array and loop through it, when it matches 'globe' just skip it, you can use implode to turn it back into a string.
Sample code:
$text = "hello,planet,globe,city,country";
$text = explode(',' , $text);
$key = array_search ('globe', $text);//just globe, no comma
echo $key;//key is 2 so
if($key == 0) {
//first word so
//first word is 'no word
} else {
echo $text[1]; //word before
}
//should also check array keys are set before using them
echo $text[3];//word after
Updated:
$string = "hello,planet globe, city,country";
$regex = '/(?:[\w-]+ ){0,1}globe,(?: [\w-]+){0,1}/is';
preg_match_all($regex, $string, $matches);
echo '<pre>';
print_r($matches);
echo '</pre>';
There is no need to use preg_match. You can just split the text and search for the index of the word and after some checks return the left and right words.
function get_left_right_word($text, $word)
{
$words = explode(',', $text);
$i = array_search($word, $words);
return array(
$i === false || $i == 0 ? 'no word' : $words[i-1],
$i === false || $i == count($words)-1 ? 'no word' : $words[i+1]
);
}
list($left_word, $right_word) = get_left_right_word('hello,planet,globe,city,country', 'globe');
echo 'left: '.$left_word.' right: '.$right_word;
This will print
left: planet right: city
If you really want to use preg_match you can use is as
function get_left_right_word($text, $word)
{
if (preg_match('/(?:(?<left>\w+),)?'.preg_quote($word, '/').'(?:,(?<right>\w+))?/', $text, $m))
{
return array(
isset($m['left']) && $m['left'] ? $m['left'] : 'no word',
isset($m['right']) && $m['right'] ? $m['right'] : 'no word'
);
}
return array(
'no word',
'no word'
);
}
I have a long array (1x75000 !) of string data.
In this array, there are repeated strings.
i want to find the array indices and the number of each repeating string.
E.g.
A=['abc' 'efg' 'hij' 'abc' 'hij' 'efg' 'klm'];
the answer should be:
2 times 'abc' at array indices 1, 4
2 times 'efg' at array indices 2, 6
2 times 'hij' at array indices 3, 5
1 time 'klm' at array indices 7
notice the large size of the array (1x75000)
This code should work:
<?php
$array = array('abc','wrerwe','wrewer','abc');
$out = array();
foreach ($array as $key => $value) {
if (!isset($out[$value])) {
$out[$value]['nr'] = 0;
$out[$value]['index'] = array();
}
++$out[$value]['nr'] ;
$out[$value]['index'][] = $key;
}
foreach ($out as $k => $v) {
echo "item ".$k." repeats ".$v['nr'].' times at positions: ';
echo implode(', ', $v['index']);
echo "<br />";
}
But so far I haven't tested in on such big array. In fact I don't think you should operate on such big arrays. You should rather divide it on smaller arrays.
I've tested it on 75000 array using code ( source for generating random string from How to create a random string using PHP? ) :
<?php
$array = randomTexts(75000);
$out = array();
foreach ($array as $key => $value) {
if (!isset($out[$value])) {
$out[$value]['nr'] = 0;
$out[$value]['index'] = array();
}
++$out[$value]['nr'] ;
$out[$value]['index'][] = $key;
}
foreach ($out as $k => $v) {
echo "item ".$k." repeats ".$v['nr'].' times at positions: ';
echo implode(', ', $v['index']);
echo "<br />";
}
function randomTexts($nr) {
$out = array();
$validString = 'abddefghihklmnopqrstuvwzyx';
for ($i=0; $i< $nr; ++$i) {
$len = mt_rand(5,10);
$out[] = get_random_string($validString, $len);
}
return $out;
}
function get_random_string($valid_chars, $length)
{
// start with an empty random string
$random_string = "";
// count the number of chars in the valid chars string so we know how many choices we have
$num_valid_chars = strlen($valid_chars);
// repeat the steps until we've created a string of the right length
for ($i = 0; $i < $length; $i++)
{
// pick a random number from 1 up to the number of valid chars
$random_pick = mt_rand(1, $num_valid_chars);
// take the random character out of the string of valid chars
// subtract 1 from $random_pick because strings are indexed starting at 0, and we started picking at 1
$random_char = $valid_chars[$random_pick-1];
// add the randomly-chosen char onto the end of our string so far
$random_string .= $random_char;
}
// return our finished random string
return $random_string;
}
It also seems to work but it takes a few seconds
I have a simple section in a PowerShell script that goes through each array in a list and grabs the data (found at [3] of the current array), using it to determine if another part of the array (found at [0]) should be added to the end of a string.
$String = "There is"
$Objects | Foreach-Object{
if ($_[3] -match "YES")
{$String += ", a " + $_[0]}
}
This works fine and dandy, resulting in a $String of something like
"There is, a car, a airplane, a truck"
But unfortunately this doesn't really make sense grammatically for what I want. I'm aware that I could either fix the string after it's been created, or include lines in the foreach/if statement that determine which characters to add. This would need to be:
$String += " a " + $_[0] - for the first match.
$String += ", a " + $_[0] - for following matches.
$String += " and a " + $_[0] + " here." - for the last match.
Furthermore I need to determine whether to use " a " if $_[0] starts with a consonant, or " an " if $_[0] starts with a vowel. All in all, I'd like the output to be
"There is a car, an airplane and a truck here."
Thanks!
Try something like this:
$vehicles = $Objects | ? { $_[3] -match 'yes' } | % { $_[0] }
$String = 'There is'
for ($i = 0; $i -lt $vehicles.Length; $i++) {
switch ($i) {
0 { $String += ' a' }
($vehicles.Length-1) { $String += ' and a' }
default { $String += ', a' }
}
if ($vehicles[$i] -match '^[aeiou]') { $String += 'n' }
$String += ' ' + $vehicles[$i]
}
$String += ' here.'
I'm working on something the whole day and night but it seems like i'm not getting any further with it cause it's a bit complicating for me to learn actually :(
The code is like this:
$aDoor = $_POST['zeilenid'];
if(empty($aDoor))
{
echo("You didn't select anything.");
}
else
{
$N = count($aDoor);
echo("You selected $N entry ID(s): ");
for($i=0; $i < $N; $i++)
{
$str = $aDoor[$i];
$str = ereg_replace(" ",",",$str);
echo($str . " ");
}
}
it doesn't work tho - i want the IDs, which will showing to NOT show them this way: 8 9 10
but rather this way: 8, 9, 10
and save it in ONE variable! how cna i make this happen? What am I doing wrong here?
just try:
$aDoor = $_POST['zeilenid'];
if(empty($aDoor))
{
echo("You didn't select anything.");
}
else
{
$N = count($aDoor);
echo("You selected $N entry ID(s): ");
echo join(", ", $aDoor);
}
join combines all elements of the array into one string and inserts the first parameter between each element
edit: save it:
$str = join(", ", $aDoor);
$clean_search = str_replace(' ', ',', $user_search);
$search_words = explode(' ', $clean_search);
$final_search_words = array();
if (count($search_words) > 0) {
$final_search_words[] = $user_search;
foreach ($search_words as $word) {
if (!empty($word)) {
$final_search_words[] = $word;
}
}
}
This code will replace empty space with comma, and the if condition is used to replace extra spaces with only one space.