How to parse page numbers like print preview does using Regex - php

If you want to print arbitrary pages on windows/office you can define it like in the picture:
So, this will print pages: 1,2,3,6,7,8
Now, I'm trying to do same thing using Regex
<?php
$str = "1-4,6,7,8";
preg_match('/((\d+-\d+)|(\d+)),((\d+-\d+)|(\d+))/',$str,$out);
print_r($out);
?>
and it prints
Array ( [0] => 1-4,6 [1] => 1-4 [2] => 1-4 [3] => [4] => 6 [5] => [6] => 6 )
but I want to is the following
Array ( [0] => 1-4 [1] => 6, [2] => 7, [3] => 7 )
How can I do this?
Here is the fiddle

Check this regexp pattern, please
$str = "1-4,6,7,8";
preg_match('/((\d+-\d+)|(\d+)),?/',$str,$out);
print_r($out);
or better use explode function:
$str = "1-4,6,7,8";
$out = explode(',', $str);
print_r($out);

Use this:
$str = "1-4,6,7,8";
preg_match_all('/(\d+(?:-\d+)?),?/', $str, $out);
print_r($out);
output:
Array
(
[0] => Array
(
[0] => 1-4,
[1] => 6,
[2] => 7,
[3] => 8
)
[1] => Array
(
[0] => 1-4
[1] => 6
[2] => 7
[3] => 8
)
)

This should do the trick:
(\d+)-?(\d*)?(,(?!$))?
Matches 1 or more numbers (mandatory).
Optional match for hyphen.
Optional match for second set of digits.
Optional comma after each set of numbers but does not allow comma on the end.
DEMO

Related

Array named capture using PHP regex

If named capture matches multiple times, is it possible to retrieve all matches?
Example
<?php
$string = 'TextToMatch [some][random][tags] SomeMoreMatches';
$pattern = "!(TextToMatch )(?P<tags>\[.+?\])+( SomeMoreMatches)!";
preg_match($pattern, $string, $matches);
print_r($matches);
Which results in
Array
(
[0] => TextToMatch [some][random][tags] SomeMoreMatches
[1] => TextToMatch
[tags] => [tags]
[2] => [tags]
[3] => SomeMoreMatches
)
Is is possible to get something like
Array
(
[0] => TextToMatch [some][random][tags] SomeMoreMatches
[1] => TextToMatch
[tags] => Array
(
[0] => [some]
[1] => [random]
[2] => [tags]
)
[2] => Array
(
[0] => [some]
[1] => [random]
[2] => [tags]
)
[3] => SomeMoreMatches
)
using only preg_match?
I am aware that I can explode tags, but I wonder if I can do this with preg_match (or similiar function) only.
Other example
$input = "Some text [many][more][other][tags][here] and maybe some text here?";
Desirable output
Array
(
[0] => Some text [many][more][other][tags][here] and maybe some text here?
[1] => Some text
[tags] => Array
(
[0] => [many]
[1] => [more]
[2] => [other]
[3] => [tags]
[4] => [here]
)
[2] => Array
(
[0] => [many]
[1] => [more]
[2] => [other]
[3] => [tags]
[4] => [here]
)
[3] => and maybe some text here?
)
You need use preg_match_all and modify the reg exp:
preg_match_all('/(?P<tags>\[.+?\])/', $string, $matches);
Just remove the + after ) to set one pattern and preg_match_all make a global search
If you need the specific answer that you posted, try with:
$string = '[some][random][tags]';
$pattern = "/(?P<tags>\[.+?\])/";
preg_match_all($pattern, $string, $matches);
$matches = [
implode($matches['tags']), end($matches['tags'])
] + $matches;
print_r($matches);
You get:
Array
(
[0] => [some][random][tags]
[1] => [tags]
[tags] => Array
(
[0] => [some]
[1] => [random]
[2] => [tags]
)
)
Since you stated in your comments that you are not actually interested in the leading substring before the set of tags, and because you stated that you don't necessarily need the named capture group (I never use them), you really only need to remove the first bit, split the string on the space after the set of tags, then split each tag in the set of tags.
Code: (Demo)
$split = explode(' ', strstr($input, '['), 2); // strstr() trims off the leading substring
var_export($split); // ^ tells explode to stop after making 2 elements
Produces:
array (
0 => '[many][more][other][tags][here]',
1 => 'and maybe some text here?',
)
Then the most direct/clean way to split those square bracketed tags, is to use the zero-width position between each closing bracket (]) and each opening bracket ([). Since only regex can isolate these specific positions as delimiters, I'll suggest preg_split().
$split[0] = preg_split('~]\K~', $split[0], -1, PREG_SPLIT_NO_EMPTY);
var_export($split); ^^- release/forget previously matched character(s)
This is the final output:
array (
0 =>
array (
0 => '[many]',
1 => '[more]',
2 => '[other]',
3 => '[tags]',
4 => '[here]',
),
1 => 'and maybe some text here?',
)
No, as Wiktor stated(1, 2), it is not possible to do using only preg_match
Solution that just works
<?php
$string = 'TextToMatch [some][random][tags] SomeMoreMatches';
$pattern = "!(TextToMatch )(?P<tags>\[.+?\]+)( SomeMoreMatches)!";
preg_match($pattern, $string, $matches);
$matches[2] = $matches["tags"] = array_map(function($s){return "[$s]";}, explode("][", substr($matches["tags"],1,-1)));
print_r($matches);

Regex match position

$str1 = '10 sold';
$re = "/(?<Alpha>[a-zA-Z]*)(?<Numeric>[0-9]*)/";
preg_match_all($re, $str1, $str1matches);
echo print_r($str1matches,1);
prints:
Array
(
[0] => Array
(
[0] => 10
[1] =>
[2] => sold
[3] =>
)
[Alpha] => Array
(
[0] =>
[1] =>
[2] => sold
[3] =>
)
[1] => Array
(
[0] =>
[1] =>
[2] => sold
[3] =>
)
[Numeric] => Array
(
[0] => 10
[1] =>
[2] =>
[3] =>
)
[2] => Array
(
[0] => 10
[1] =>
[2] =>
[3] =>
)
)
But why does it print such a long array, and how do I determine at which position will my values (xxx and label) be available always?
I'd use a simple /^([0-9]+)\s*([a-zA-Z]+)$/ regex since you confirm there is a number and then a word in the input string:
preg_match('/^([0-9]+)\s*([a-zA-Z]+)$/', '10 sold', $str1matches, PREG_OFFSET_CAPTURE);
See the PHP demo:
$str1 = '10 sold';
$re = "/^([0-9]+)\s*([a-zA-Z]+)$/";
preg_match($re, $str1, $str1matches, PREG_OFFSET_CAPTURE);
echo print_r($str1matches[1]);
echo print_r($str1matches[2]);
The $str1matches[1] will contain an array with the Group 1 (number) value and its position, and the $str1matches[2] will contain an array with the Group 2 (word) value and its position.

Unexpected preg_match result from pattern with "?:"

I try this pattern
(?:(\d+)\/|)reports\/(\d+)-([\w-]+).html
with this string (preg_match with modifiers "Axu")
reports/683868-derger-gergewrger.html
and i expected this matched result (https://regex101.com/r/kX6yZ5/1):
[1] => 683868
[2] => derger-gergewrger
But i get this:
[1] =>
[2] => 683868
[3] => derger-gergewrger
Why? Where does the empty value (1), because the pattern should not capture "?:"
I have two cases:
"reports/683868-derger-gergewrger.html"
"757/reports/683868-derger-gergewrger.html"
at first case, i need two captures, but at second case i need three captures.
You can use:
preg_match('~(?:\d+/)?reports/(\d+)-([\w-]+)\.html~',
'reports/683868-derger-gergewrger.html', $m);
print_r($m);
Array
(
[0] => reports/683868-derger-gergewrger.html
[1] => 683868
[2] => derger-gergewrger
)
EDIT: You probably want this behavior:
$s = '757/reports/683868-derger-gergewrger.html';
preg_match('~(?|(\d+)/reports/(\d+)-([\w-]+)\.html|reports/(\d+)-([\w-]+)\.html)~',
$s, $m); print_r($m);Array
(
[0] => 757/reports/683868-derger-gergewrger.html
[1] => 757
[2] => 683868
[3] => derger-gergewrger
)
and:
$s = 'reports/683868-derger-gergewrger.html';
preg_match('~(?|(\d+)/reports/(\d+)-([\w-]+)\.html|reports/(\d+)-([\w-]+)\.html)~',
$s, $m); print_r($m);
Array
(
[0] => reports/683868-derger-gergewrger.html
[1] => 683868
[2] => derger-gergewrger
)
(?|..) is a Non-capturing group. Subpatterns declared within each alternative of this construct will start over from the same index.

split text into parts

I wanted to split a large text into 10 pieces (somehow equal parts).
Ii use this function:
<?php
function chunk($msg) {
$msg = preg_replace('/[\r\n]+/', ' ', $msg);
//define character length of each text piece
$chunks = wordwrap($msg, 10000, '\n');
return explode('\n', $chunks);
}
$arrayys=chunk($t);
foreach($arrayys as $partt){echo $partt."<br/><br/><br/>";}
?>
But is it possible to define word length of each text piece (not character length )? how to divide text into words in such situation?
I would suggest to use "explode"
http://php.net/manual/en/function.explode.php
for splitting the string by spaces. Then you'll get an array of words on which you can iterate and build your text-parts.
From docs,
<?php
$text = "ABCDEFGHIJK.";
$newtext = wordwrap($text,3,"\n",true);
echo "$newtext\n";
?>
OUTPUT: ABC DEF GHI JK.
You can do something like this. Breaks your text into equal parts.. The text in $str is of 20 chars, So the text is broken into 10 parts with 2 chars as a set.
Say, if your large text is of 1000 characters, then you will be getting 100 equal parts of text.
<?php
$div=10;//Equally split into 10 ...
$str="abcdefghijklmnopqrst";
print_r(array_chunk(str_split($str), (strlen($str)/($div))));
OUTPUT:
Array
(
[0] => Array
(
[0] => a
[1] => b
)
[1] => Array
(
[0] => c
[1] => d
)
[2] => Array
(
[0] => e
[1] => f
)
[3] => Array
(
[0] => g
[1] => h
)
[4] => Array
(
[0] => i
[1] => j
)
[5] => Array
(
[0] => k
[1] => l
)
[6] => Array
(
[0] => m
[1] => n
)
[7] => Array
(
[0] => o
[1] => p
)
[8] => Array
(
[0] => q
[1] => r
)
[9] => Array
(
[0] => s
[1] => t
)
)

How can I split a list with multiple delimiters?

Basically, I want to enter text into a text area, and then use them. For example
variable1:variable2#variable3
variable1:variable2#variable3
variable1:variable2#variable3
I know I could use explode to make each line into an array, and then use a foreach loop to use each line separately, but how would I separate the three variables to use?
Besides preg_split:
$line = 'variable11:variable12#variable13';
print_r(preg_split('/[:#]/', $line));
/*
Array
(
[0] => variable11
[1] => variable12
[2] => variable13
)
*/
you could do a preg_match_all:
$text = 'variable11:variable12#variable13
variable21:variable22#variable23
variable31:variable32#variable33';
preg_match_all('/([^\r\n:]+):([^\r\n#]+)#(.*)\s*/', $text, $matches, PREG_SET_ORDER);
print_r($matches);
/*
Array
(
[0] => Array
(
[0] => variable11:variable12#variable13
[1] => variable11
[2] => variable12
[3] => variable13
)
[1] => Array
(
[0] => variable21:variable22#variable23
[1] => variable21
[2] => variable22
[3] => variable23
)
[2] => Array
(
[0] => variable31:variable32#variable33
[1] => variable31
[2] => variable32
[3] => variable33
)
)
*/
try preg_split http://php.net/manual/en/function.preg-split.php
if necessary, you could make several calls to "explode"
http://jp.php.net/manual/en/function.explode.php

Categories