Using PHP I sometimes have strings that look like the following:
111
110
011
1111
0110012
What is the most efficient way (preferably without regex) to determine if a string contains any character other then the character 1?
Here's a one-line code solution that can be put into a conditional etc.:
strlen(str_replace('1','',$mystring))==0
It strips out the "1"s and sees if there's anything left.
User Don't Panic commented that str_replace could be replaced by trim:
strlen(trim($mystring, '1'))==0
which removes leading and trailing 1s and sees if there's anything left. This would work for the particular case in OP's request but the first option will also tell you how many non-"1" characters you have (if that information matters). Depending on implementation, trim might run slightly faster because PHP doesn't have to check any characters between the first and last non-"1" characters.
You could also use a string like a character array and iterate through from the beginning until you find a character which is not =='1' (in which case, return true) or reach the end of the array (in which case, return false).
Finally, though OP here said "preferably without regex," others open to regexes might use one:
preg_match("/[^1]/", $mystring)==1
Another way to do it:
if (base_convert($string, 2, 2) === $string) {
// $string has only 0 and 1 characters.
}
since your $string is basically a binary number, you can check it with base_convert.
How it works:
var_dump(base_convert('110', 2, 2)); // 110
var_dump(base_convert('11503', 2, 2)); // 110
var_dump(base_convert('9111111111111111111110009', 2, 2)); // 11111111111111111111000
If the returned value of base_convert is different from the input, there're something other characters, beside 0 and 1.
If you want checks if the string has only 1 characters:
if(array_sum(str_split($string)) === strlen($string)) {
// $string has only 1 characters.
}
You retrieve all the single numbers with str_split, and sum them with array_sum. If the result isn't the same as the length of the string, then you've other number in the string beside 1.
Another option is treat string like array of symbols and check for something that is not 1. If it is - break for loop:
for ($i = 0; $i < strlen($mystring); $i++) {
if ($mystring[$i] != '1') {
echo 'FOUND!';
break;
}
}
Related
I have a string /en/products/saucony-switchback-iso/416.html and I would like to replace the first 4th character /en/ with /de/.
The result should be /de/products/saucony-switchback-iso/416.html
This is what I've tried:
$href = "/en/products/saucony-switchback-iso/416.html";
$href_replace = substr_replace($href, "/de/", 0);
its only returning "/de/"?
You also need to define the length of how much you're replacing in the string, which in your case is 4 (or 3, seeing as the trailing / is present in both) characters.
$href = "/en/products/saucony-switchback-iso/416.html";
$href_replace = substr_replace($href, "/de/", 0, 4);
echo $href_replace;
If you don't define a length as in your example, it defaults to the entire length of the string http://php.net/manual/en/function.substr-replace.php
length
If given and is positive, it represents the length of the portion of
string which is to be replaced. If it is negative, it represents the
number of characters from the end of string at which to stop
replacing. If it is not given, then it will default to strlen( string
); i.e. end the replacing at the end of string
Which is why you're only being left with /de/
If you want to replace /en/, str_replace is a better function
echo str_replace("/en/", "/de/", $href);
Technically you only need to do 3 (but whatever), it's simple.
echo "/de" .substr("/en/products/saucony-switchback-iso/416.html", 3);
Output
/de/products/saucony-switchback-iso/416.html
Sandbox
I also think substr will be about as fast as you can get it.
I have some PHP code that accepts an uploaded file from an HTML form then reads through it using regex to look for specific lines (in the case below, those with "Number" followed by an integer).
The regex matches the integers like I want it to, but of course they're returned as strings in $matches. I need to check if the integer is between 0 and 9 but I um unable to do this no matter what I try.
Using intval() or (int) to first convert the matches to integers always returns 0 even though the given string contains only integers. And using in_array to compare the integer to an array of 0-9 as strings always returns false as well for some reason. Here's the trouble code...
$myFile = file($myFileTmp, FILE_IGNORE_NEW_LINES);
$numLines = count($myFile) - 1;
$matches = array();
$nums = array('0','1','2','3','4','5','6','7','8','9');
for ($i=0; $i < $numLines; $i++) {
$line = trim($myFile[$i]);
$numberMatch = preg_match('/Number(.*)/', $line, $matches);
if ($numberMatch == 1 and ctype_space($matches[1]) == False) { // works up to here
$number = trim($matches[1]); // string containing an integer only
echo(intval($number)); // conversion doesn't work - returns 0 regardless
if (in_array($number,$nums)) { // searching in array doesn't work - returns FALSE regardless
$number = "0" . $number;
}
}
}
I've tried type checking, double quotes, single quotes, trimming whitespace, UTF8 encoding...what else could it possibly be? I'm about to give up on this app entirely, please save me.
Use '===' for eq for example
if 1 == '1' then true;
if 1 === '1' false;
if 1 == true then true;
if 1 === true then false
You can show file?
You write in your question that you're using a regular expression to look for the term "Number" followed by a single digit (0-9).
A regular expression for it would be:
/Number(\d)/
It will contain in the matching group 1 the number (digit) you're looking for.
The pattern you use:
/Number(.*)/
can contain anything (but a line-break) in the first matching group. It obviously is matching too much. You then have a problem filtering that too much retro-actively.
It normally works best to first look as precise as possible than to fiddle with too much noise afterwards.
I've got a large string that I want to put in an array after each 50 words. I thought about using strsplit to cut, but realised that wont take the words in to consideration, just split when it gets to x char.
I've read about str_word_count but can't work out how to put the two together.
What I've got at the moment is:
$outputArr = str_split($output, 250);
foreach($outputArr as $arOut){
echo $arOut;
echo "<br />";
}
But I want to substitute that to form each item of the array at 50 words instead of 250 characters.
Any help will be much appreciated.
Assuming that str_word_count is sufficient for your needs¹, you can simply call it with 1 as the second parameter and then use array_chunk to group the words in groups of 50:
$words = str_word_count($string, 1);
$chunks = array_chunk($words, 50);
You now have an array of arrays; to join every 50 words together and make it an array of strings you can use
foreach ($chunks as &$chunk) { // important: iterate by reference!
$chunk = implode(' ', $chunk);
}
¹ Most probably it is not. If you want to get what most humans consider acceptable results when processing written language you will have to use preg_split with some suitable regular expression instead.
There's another way:
<?php
$someBigString = <<<SAMPLE
This, actually, is a nice' old'er string, as they said, "divided and conquered".
SAMPLE;
// change this to whatever you need to:
$number_of_words = 7;
$arr = preg_split("#([a-z]+[a-z'-]*(?<!['-]))#i",
$someBigString, $number_of_words + 1, PREG_SPLIT_DELIM_CAPTURE);
$res = implode('', array_slice($arr, 0, $number_of_words * 2));
echo $res;
Demo.
I consider preg_split a better tool (than str_word_count) here. Not because the latter is inflexible (it is not: you can define what symbols can make up a word with its third param), but because preg_split will essentially stop processing the string after getting N items.
The trick, as quite common with this function, is to capture delimiters as well, then use them to reconstruct the string with the first N words (where N is given) AND punctuation marks saved.
(of course, the regex used in my example does not strictly comply to str_word_count locale-dependent behavior. But it still restricts the words to consist of alpha, ' and - symbols, with the latter two not at the beginning and the end of any word).
I want to know is there any way to split text like this:
123456789 into 123-456-789
as to add "-" after every 3 characters?
Just wanted to know, as I know the reverse, but how to do this is over my head. ;)
and also if the text is
ABCDEFGHI OR A1B2C3D4E or any other format
without any space between the characters !
language: PHP only
<?php
$i = '123456789';
echo 'result: ', wordwrap($i, 3, '-', true);printsresult: 123-456-789
see http://php.net/wordwrap
I'm not a big fan of regexes for simple string extraction (especially fixed length extractions), preferring them for slightly more complex stuff. Almost every language has a substring function so, presuming your input has already been validated, a simple (pseudo-code since you haven't specified a language):
s = substring (s,0,3) + "-" + substring (s,3,3) + "-" + substring (s,6,3)
If you want it every three characters for a variable length string (with odd size at the end):
t = ""
sep = ""
while s != "":
if s.len <= 3:
t = t + sep + s
s = ""
else:
t = t + sep + substring (s,0,3)
s = substring (s,3)
sep = "-"
s = t
For any language:
Create an empty string variable called "result"
Create an integer counter variable, "i", which increments until the length of the original string (the one with the number)
Append each character from the original string to "result"
If i modulo 3 (usually % or mod) is zero, append a dash to "result"
In the interest of completeness, here is a Python solution:
>>> a = "123456789"
>>> a[0:3] + "-" + a[3:6] + "-" + a[6:9]
'123-456-789'
Since you updated your question to specify a PHP solution, this should work:
substr($a, 0, 3) . "-" . substr($a, 3, 3) . "-" . substr($a, 6, 3)
See substr for more information on this function. This will work not only for digits, but for alphabetic characters too.
Yet another Python version:
>>> x="123456789"
>>> out=[x[i:i+3] for i in xrange(0, len(x), 3)]
>>> print "-".join(out)
123-456-789
I think that this can be sanely done in a regex with lookahead:
s/(.{3})(?=.)/$1-/g
Since you mentioned PHP in a comment:
preg_replace ("/(.{3})(?=.)/", "$1-", $string);
edit: After VolkerK showed wordwrap, I found chunk-split in the documentation:
$new_string = chunk_split ($string, 3, '-');
This has the advantage that it also works when there are spaces in the string (wordwrap would prefer to break at the spaces).
In Perl:
#!/usr/bin/perl
use strict;
use warnings;
my $string = "123456789";
$string =~ /(\d{3})(\d{3})(\d+)/;
print "$1-$2-$3"
You can do it with (among other means) a regular expression match and replace. The exact syntax depends on the tool or programming language you are using. For instance, one way to do it in Perl would be
$a = "123456789";
$a =~ s/(\d{3})/$1-/g;
chop($a);
print $a;
Line 2 replaces every 3 digits for the same 3 digits and a dash. With chop() we delete the trailing dash.
There is another question here. What to do when the string doesn't contain a multiple by 3 amount of digits? If such strings were allowed, then the above snippet would need modification.
Also, depending on the specifics of the case, you might get away with simple substring replacement, or string slicing.
One more Perl example. This doesn't remove final groups smaller than three, and it leaves initial groups of less than three digits alone. It's based (pretty shamelessly) on the "money numbers" example in Learning Perl (page 212 of the 5th ed):
#!/usr/bin/env perl
use strict;
use warnings;
print "Gimme' a number: ";
chomp(my $number = <STDIN>);
1 while ($number =~ s/([0-9]{3})([0-9]+)/$1-$2/);
print "Now it's $number\n";
I have a form in which people will be entering dollar values.
Possible inputs:
$999,999,999.99
999,999,999.99
999999999
99,999
$99,999
The user can enter a dollar value however they wish. I want to read the inputs as doubles so I can total them.
I tried just typecasting the strings to doubles but that didn't work. Total just equals 50 when it is output:
$string1 = "$50,000";
$string2 = "$50000";
$string3 = "50,000";
$total = (double)$string1 + (double)$string2 + (double)$string3;
echo $total;
A regex won't convert your string into a number. I would suggest that you use a regex to validate the field (confirm that it fits one of your allowed formats), and then just loop over the string, discarding all non-digit and non-period characters. If you don't care about validation, you could skip the first step. The second step will still strip it down to digits and periods only.
By the way, you cannot safely use floats when calculating currency values. You will lose precision, and very possibly end up with totals that do not exactly match the inputs.
Update: Here are two functions you could use to verify your input and to convert it into a decimal-point representation.
function validateCurrency($string)
{
return preg_match('/^\$?(\d{1,3})(,\d{3})*(.\d{2})?$/', $string) ||
preg_match('/^\$?\d+(.\d{2})?$/', $string);
}
function makeCurrency($string)
{
$newstring = "";
$array = str_split($string);
foreach($array as $char)
{
if (($char >= '0' && $char <= '9') || $char == '.')
{
$newstring .= $char;
}
}
return $newstring;
}
The first function will match the bulk of currency formats you can expect "$99", "99,999.00", etc. It will not match ".00" or "99.", nor will it match most European-style numbers (99.999,00). Use this on your original string to verify that it is a valid currency string.
The second function will just strip out everything except digits and decimal points. Note that by itself it may still return invalid strings (e.g. "", "....", and "abc" come out as "", "....", and ""). Use this to eliminate extraneous commas once the string is validated, or possibly use this by itself if you want to skip validation.
You don't ever want to represent monetary values as floats!
For example, take the following (seemingly straight forward) code:
$x = 1.0;
for ($ii=0; $ii < 10; $ii++) {
$x = $x - .1;
}
var_dump($x);
You might assume that it would produce the value zero, but that is not the case. Since $x is a floating point, it actually ends up being a tiny bit more than zero (1.38777878078E-16), which isn't a big deal in itself, but it means that comparing the value with another value isn't guaranteed to be correct. For example $x == 0 would produce false.
http://p2p.wrox.com/topic.asp?TOPIC_ID=3099
goes through it step by step
[edit] typical...the site seems to be down now... :(
not a one liner, but if you strip out the ','s you can do: (this is pseudocode)
m/^\$?(\d+)(?:\.(\d\d))?$/
$value = $1 + $2/100;
That allows $9.99 but not $9. or $9.9 and fails to complain about missplaced thousands separators (bug or feature?)
There is a potential 'locality' issue here because you are assuming that thousands are done with ',' and cents as '.' but in europe it is opposite (e.g. 1.000,99)
I recommend not to use a float for storing currency values. You can get rounding errors if the sum gets large. (Ok, if it gets very large.)
Better use an integer variable with a large enough range, and store the input in cents, not dollars.
I belive that you can accomplish this with printf, which is similar to the c function of the same name. its parameters can be somewhat esoteric though. you can also use php's number_format function
Assuming that you are getting real money values, you could simply strip characters that are not digits or the decimal point:
(pseudocode)
newnumber = replace(oldnumber, /[^0-9.]/, //)
Now you can convert using something like
double(newnumber)
However, this will not take care of strings such as "5.6.3" and other such non-money strings. Which raises the question, "Do you need to handle badly formatted strings?"