two regex tests within regex - for-loop

now i have got a problem with preg_match.
This is an example string: "!asksheet!H69=var8949", there can also be more than one var8949 or H69 index in this row. Result shoud be "var33333=var8949"
This is my part:
preg_match_all('#\b\!(.*)\![A-Z]{1,3}\d+\b#', $output, $matches2);
foreach ($matches2[0] as $match2) {
$result6 = $db->query("SELECT varid FROM variablen WHERE varimportedindex = '".$match2."' AND projectid = $pid AND varsheetname LIKE '%".$match2."%' ");
$rowoperation2 = $result6->fetch_assoc();
if ($rowoperation2['varid'] != "" AND $rowoperation2['varid'] != "0") {
$output2 = preg_replace("#\b\!(.*)\![A-Z]{1,3}\d+\b#", "var".$rowoperation2['varid']."", $output);
}
}
Can someone perhaps help?
Thank you,
Regards
Olaf

Why not using a simple preg_match instead of preg_match_all, you don't need word boundary and exclamation mark doesn't need to be escaped, the strings you're looking for are in group 1 and 2:
$str = '"!asksheet!H69=var8949"';
preg_match('#!(.*?)!([A-Z]{1,3}\d+)#', $str, $m);
print_r($m);
Output:
Array
(
[0] => !asksheet!H69
[1] => asksheet
[2] => H69
)

Related

PHP preg_match unknown modifier error

Message: preg_match(): Unknown modifier 'p'
Filename: core/Router.php
Line Number: 399
Backtrace:
File: /home/spdcin/public_html/demo/no-waste/index.php
Line: 292
Function: require_once
iam getting this error on line 2
$key = str_replace(array(':any', ':num'), array('[^/]+', '[0-9]+'), $key);
// Does the RegEx match?
//line no 2
if (preg_match('#^'.$key.'$#', $uri, $matches))
{
// Are we using callbacks to process back-references?
if ( ! is_string($val) && is_callable($val))
{
// Remove the original string from the matches array.
array_shift($matches);
// Execute the callback using the values in matches as its parameters.
$val = call_user_func_array($val, $matches);
}
// Are we using the default routing method for back-references?
elseif (strpos($val, '$') !== FALSE && strpos($key, '(') !== FALSE)
{
$val = preg_replace('#^'.$key.'$#', $val, $uri);
}
$this->_set_request(explode('/', $val));
return;
}
}
There is a problem with your regex and PHP thinks you try to apply a 'p' modifier, which is not valid.
You will probably get to know what is wrong with your regex if you do :
echo '#^'.$key.'$#';
The fact that you try to program a router indicates that $key most probably contains '#p' (common in URLs).
Solution : In your case you can escape the character '#' with backslashes. Quoted from the php documentation :
"If the delimiter needs to be matched inside the pattern it must be escaped using a backslash."
If I understand your problem correctly, surround $key with preg_quote() like this:
if (preg_match('#^'.preg_quote($key).'$#', $uri, $matches))
This function will automatically escape ALL regex commands in $key.

Parsing a string field

I have these Syslog messages:
N 4000000 PROD 15307 23:58:12.13 JOB78035 00000000 $HASP395 GGIVJS27 ENDED\r
NI0000000 PROD 15307 23:58:13.41 STC81508 00000200 $A J78036 /* CA-JOBTRAC JOB RELEASE */\r
I would like to parse these messages into various fields in a Hash, e.g.:
event['recordtype'] #=> "N"
event['routingcode'] #=> "4000000"
event['systemname'] #=> "PROD"
event['datetime'] #=> "15307 23:58:12.13"
event['jobid'] #=> "JOB78035"
event['flag'] #=> "00000000"
event['messageid'] #=> "$HASP395"
event['logmessage'] #=> "$HASP395 GGIVJS27 ENDED\r"
This is the code I have currently:
message = event["message"];
if message.to_s != "" then
if message[2] == " " then
array = message.split(%Q[ ]);
event[%q[recordtype]] = array[0];
event[%q[routingcode]] = array[1];
event[%q[systemname]] = array[2];
event[%q[datetime]] = array[3] + " " +array[4];
event[%q[jobid]] = message[38,8];
event[%q[flags]] = message[47,8];
event[%q[messageid]] = message[57,8];
event[%q[logmessage]] = message[56..-1];
else
array = message.split(%Q[ ]);
event[%q[recordtype]] = array[0][0,2];
event[%q[routingcode]] = array[0][2..-1];
event[%q[systemname]] = array[1];
event[%q[datetime]] = array[2] + " "+array[3];
event[%q[jobid]] = message[38,8];
event[%q[flags]] = message[47,8];
event[%q[messageid]] = message[57,8];
event[%q[logmessage]] = message[56..-1];
end
end
I'm looking to improve the above code. I think I could use a regular expression, but I don't know how to approach it.
You can't use split(' ') or a default split to process your fields because you are dealing with columnar data that has fields that have no whitespace between them, resulting in your array being off. Instead, you have to pick apart each record by columns.
There are many ways to do that but the simplest and probably fastest, is indexing into a string and grabbing n characters:
'foo'[0, 1] # => "f"
'foo'[1, 2] # => "oo"
The first means "starting at index 0 in the string, grab one character." The second means "starting at index 1 in the string, grab two characters."
Alternately, you could tell Ruby to extract by ranges:
'foo'[0 .. 0] # => "f"
'foo'[1 .. 2] # => "oo"
These are documented in the String class.
This makes writing code that's easily understood:
record_type = message[ 0 .. 1 ].rstrip
routing_code = message[ 2 .. 8 ]
system_name = message[ 10 .. 17 ]
Once you have your fields captured add them to a hash:
{
'recordtype' => record_type,
'routingcode' => routing_code,
'systemname' => system_name,
'datetime' => date_time,
'jobid' => job_id,
'flags' => flags,
'messageid' => message_id,
'logmessage' => log_message,
}
While you could use a regular expression there's not much gained using one, it's just another way of doing it. If you were picking data out of free-form text it'd be more useful, but in columnar data it tends to result in visual noise that makes maintenance more difficult. I'd recommend simply determining your columns then cutting the data you need based on those from each line.

preg_replace technicality in PHP regular expressions

My current code:
$text = "This is my string exec001 and this is the rest of the string exec222 and here is even more execSOMEWORD a very long string!";
$text2 = preg_replace('/\bexec(\S+)/', "<html>$1</html><div>$1</div>",, $text);
echo $text2,"\n";
Outputs the following:
This is my string <html>001</html><div>001</div> and this is the rest of the string <html>222</html><div>222</div> and here is even more <html>SOMEWORD</html><div>SOMEWORD</div> a very long string!
My question is, how can I store multiple variables? For example: I want to replace execVARIABLE1:VARIABLE2:VARIABLE3 and store each of VARIABLE1, 2 and 3 in say $1, $2 and $3 when the string is rewritten.
In order to save the matched groups you can use preg_match():
$text = "This is my string exec001 and this is the rest of the string exec222 and here is even more execSOMEWORD a very long string!";
preg_match( '/.*?\bexec(\S+).*?\bexec(\S+).*?\bexec(\S+)/', $text, $matches);
print_r($matches);
OUTPUT
Array
(
[0] => This is my string exec001 and this is the rest of the string exec222 and here is even more execSOMEWORD
[1] => 001
[2] => 222
[3] => SOMEWORD
)
Thanks to M42, we have the correct answer as follows:
$text2 = preg_replace('/\bexec([^:\s]+):([^:\s]+)/', "<html>$1</html><div>$2</div>", $text);

Algorithm: optimally distribute N people among M tasks given P preferences

Example: 10 candidates each give 2 preferences (the first being more preferred than the second) for 3 available jobs, and their boss must then optimally allocate (and evenly distribute) them evenly based on their preferences. Obviously, unwanted jobs will require some random draw.
How would I write an algorithm that calculates this optimal allocation automatically?
I looked around and found bipartite graphs which might give me some clues, however I am having trouble wrapping my head around it!
For the "luck" aspect of the game, I already implemented a simple Fisher Yates Shuffle.
Preference weight:
If there are 2 preferences, when assigned to a worker, obtaining a first choice weighs +2, a second choice +1, an unwanted choice -1 (for example). The "optimality" goal is to maximize the aggregate preferences.
Your question is quite challenging, but i found a working (maybe not the most performant) solution. My Example is written in PHP, but you should be able to adapt it. I'll try to explain the "thoughts" behind the code.
Note: It seems like you added the "10 persons, 3 Jobs" constraint later - or i simple did overread it. However, my code should give you an example that you might be able to adapt to that constraint. My Code currently is assuming that there are n jobs for n persons. (The most easiest way of adapting it to the 10/3 criteria, would be to split up the 3 Jobs into 10 equal units of work, when assuming 10 workers!)
First, lets create some basic architecture stuff. We need person, job and obviously a matrix, representing the satisfaction of a person towards a job. The following snipped does exactly that:
<?php
class Person{
var $name;
var $prim;
var $sec;
function __construct($name, $prim, $sec){
$this->name = $name;
$this->prim = $prim;
$this->sec = $sec;
}
function likes($job){
if ($job->type == $this->prim) return 2;
if ($job->type == $this->sec) return 1;
else return -1;
}
}
class Job{
var $name;
var $type;
function __construct($name, $type){
$this->name = $name;
$this->type = $type;
}
}
$persons = array(
"Max" => new Person("Max", "programing", "testing"),
"Peter" => new Person("Peter", "testing", "docu"),
"Sam" => new Person("Sam", "designing", "testing")
);
$jobs = array(
"New Classes" => new Job("New Classes", "programing"),
"Theme change" => new Job("Theme change", "designing"),
"Test Controller" => new Job("Test Controller", "testing")
);
// debug: draw it:
echo "<h2>Happines with Jobs</h2> ";
echo "<table border=1>";
$p=0;
echo "<tr>";
foreach ($jobs AS $job){
$j=0;
foreach ($persons as $person){
if ($p++==0){
echo "<tr><td></td>";
foreach ($persons as $per) {
echo "<td>".$per->name."</td>";
}
echo "</tr>";
}
if ($j++==0){
echo "<td>".$job->name."</td>";
}
echo "<td>".$person->likes($job)."</td>";
}
echo "</tr>";
}
echo "</table>";
This will give you a table like this:
Second, we need to create ALL permutations of jobs and persons. (actually we don't need to, but doing so, will show you the reason, why we don't need to!)
To create all permutations, we are using just the name of a person or job. (we can resolve the name back to the actual object later)
//build up all permutations
$personNames = array();
foreach ($persons AS $person){
$personNames[] = $person->name;
}
$jobNames = array();
foreach ($jobs AS $job){
$jobNames[] = $job->name;
}
$personsPerms = array();
pc_permute($personNames,$personsPerms);
$jobsPerms = array();
pc_permute($jobNames,$jobsPerms);
function pc_permute($items, &$result, $perms = array( )) {
if (empty($items)) {
$result[] = join('/', $perms);
} else {
for ($i = count($items) - 1; $i >= 0; --$i) {
$newitems = $items;
$newperms = $perms;
list($foo) = array_splice($newitems, $i, 1);
array_unshift($newperms, $foo);
pc_permute($newitems,$result, $newperms);
}
}
}
Now, we have 2 Arrays: All job permutations and all person permutations.
For the Example given above, the arrays will look like this (3 Elements each, makes 3*2*1=6 Permutations per Array):
Array
(
[0] => Max/Peter/Sam
[1] => Peter/Max/Sam
[2] => Max/Sam/Peter
[3] => Sam/Max/Peter
[4] => Peter/Sam/Max
[5] => Sam/Peter/Max
)
Array
(
[0] => New Classes/Theme change/Test Controller
[1] => Theme change/New Classes/Test Controller
[2] => New Classes/Test Controller/Theme change
[3] => Test Controller/New Classes/Theme change
[4] => Theme change/Test Controller/New Classes
[5] => Test Controller/Theme change/New Classes
)
Now, We can create a nXn Table, containing ALL Values of the overall satisfaction for ALL possible job allocations:
// debug: draw it:
echo "<h2>Total Happines of Combination (full join)</h2> ";
echo "<table border=1>";
$p=0;
echo "<tr>";
$row = 0;
$calculated = array();
foreach ($jobsPerms AS $jobComb){
$j=0;
$jobs_t = explode("/", $jobComb);
foreach ($personsPerms as $personComb){
if ($p++==0){
echo "<tr><td></td>";
foreach ($personsPerms as $n) {
echo "<td>".$n."</td>";
}
echo "</tr>";
}
if ($j++==0){
echo "<td>".$jobComb."</td>";
}
$persons_t = explode("/", $personComb);
$h = 0;
echo "<td>";
for ($i=0; $i< count($persons_t); $i++){
$h += $persons[$persons_t[$i]]->likes($jobs[$jobs_t[$i]]);
}
echo $h;
echo "</td>";
}
$col=0;
$row++;
echo "</tr>";
}
echo "</table>";
Lets call this matrix "M"
This Matrix contains a "lot" of double combinations: (a/b) TO (1/2) is equal to (b/a) to (2/1) etc...
After all: We simple can ignore:
Either Each row > 1
OR Each column > 1
Ignoring all Columns > 1:
echo "<h2>Total Happines of Combination (ignoring columns)</h2> ";
echo "<table border=1>";
$p=0;
echo "<tr>";
$row = 0;
$calculated = array();
foreach ($jobsPerms AS $jobComb){
$j=0;
$jobs_t = explode("/", $jobComb);
$col = 0;
$personComb = $personsPerms[0];
if ($p++==0){
echo "<tr><td></td>";
echo "<td>".$personsPerms[0]."</td>";
echo "</tr>";
}
if ($j++==0){
echo "<td>".$jobComb."</td>";
}
$persons_t = explode("/", $personComb);
$h = 0;
echo "<td>";
for ($i=0; $i< count($persons_t); $i++){
$h += $persons[$persons_t[$i]]->likes($jobs[$jobs_t[$i]]);
}
echo $h;
echo "</td>";
$col=0;
$row++;
echo "</tr>";
}
echo "</table>";
Output:
And there you go! In this Example (one of) the most satisfying Solution would be:
Max -> New Classes (+2)
Peter -> Test Controller (+2)
Sam -> Theme Change (+2)
-> Happiness: 6.
There are other, equal distributions as well.
Example: 6 persons / 6 jobs:
$persons = array(
"Max" => new Person("Max", "programing", "testing"),
"Peter" => new Person("Peter", "testing", "docu"),
"Sam" => new Person("Sam", "designing", "testing"),
"Jeff" => new Person("Jeff", "docu", "programing"),
"Fred" => new Person("Fred", "programing", "designing"),
"Daniel" => new Person("Daniel", "designing", "docu")
);
$jobs = array(
"New Classes" => new Job("New Classes", "programing"),
"Theme change" => new Job("Theme change", "designing"),
"Test Controller" => new Job("Test Controller", "testing"),
"Create Manual" => new Job("Create Manual", "docu"),
"Program more!" => new Job("Program more!", "programing"),
"Style the frontend" => new Job("Style the frontend", "designing")
);
results in (Persons: Max / Peter / Sam / Jeff / Fred / Daniel)
Assuming by "evenly distribute" you mean you know how many people must be assigned to each project, this is the weighted matching problem (aka "maximum cardinality bipartite matching"). Just treat each open position (rather than each job) as a node - so, a job with 3 positions will have three nodes.
The wikipedia article gives several solutions.
Pseudocode
for(n to number of jobs left)
{
job n = a random candidate
if(random candidate first preference == job n)
remove random candidate from list and remove job from list
}
if(jobs left)
{
for(n to number of jobs left)
for(i to number of candidates)
if(candidate first preference == job n)
{
job n = candidate i
remove candidate i from list and remove job n from list
}
else if(candidate second preference == job n)
{
job n = candidate i
}
}

Algorithm to do numeric profile of the string

I have few file similar to below, and I am trying to do numeric profiling as mentioned in the image
>File Sample
attttttttttttttacgatgccgggggatgcggggaaatttccctctctctctcttcttctcgcgcgcg
aaaaaaaaaaaaaaagcgcggcggcgcggasasasasasasaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
I have to map each substring of size 2 and then map it to 33 value for different ptoperties and then add as per the window size of 5.
my %temp = (
aCount => {
aa =>2
}
cCount => {
aa => 0
}
);
My current implementation include as per below ,
while (<FILE>) {
my $line = $_;
chomp $line;
while ($line=~/(.{2})/og) {
$subStr = $1;
if (exists $temp{aCount}{$subStr}) {
push #{$temp{aCount_array}},$temp{aCount}{$subStr};
if (scalar(#{$temp{aCount_array}}) == $WINDOW_SIZE) {
my $sum = eval (join('+',#{$temp{aCount_array}}));
shift #{$temp{aCount_array}};
#Similar approach has been taken to other 33 rules
}
}
if (exists $temp{cCount}{$subStr}) {
#similar approach
}
$line =~s/.{1}//og;
}
}
is there any other approach to increase the speed of the overall process
Regular expressions are awesome, but they can be overkill when all you need are fixed width substrings. Alternatives are substr
$len = length($line);
for ($i=0; $i<$len; $i+=2) {
$subStr = substr($line,$i,2);
...
}
or unpack
foreach $subStr (unpack "(A2)*", $line) {
...
}
I don't know how much faster either of these will be than regular expressions, but I know how I would find out.

Resources