Hello everyone I'm working on something where I'm going to take a person's ID from a string, which is after that person's name. So how it works, is a POST value is stored in a variable. In this case, $user = "Himatochi". I want to select the users ID (its a SteamID, if that matters) which comes right after their name in a string. But it should be noted that there are more than 1 players and ID's listed in the string.
So right now here's the string I have
hostname: Development Server version : 14.09.08/24 5914 secure udp/ip
: 192.168.1.4:27015 (public ip: 135.120.128.85) map : gm_flatgrass at:
0 x, 0 y, 0 z players : 2 (16 max) # userid name uniqueid connected
ping loss state adr # 2 "Chalu87" STEAM_0:1:70377242 05:01 35 0 active
192.168.1.4:27006 # 4 "Himatochi" STEAM_0:0:53654842 01:13 267 0 active 105.20.142.139:27005
So I basically want code that tells PHP to store the SteamID after $user into a new variable.
You could use a regex to accomplish this, assuming the data structure is consistent and $user is always set.
<?php
$user = 'Himatochi';
$data = 'hostname: Development Server version : 14.09.08/24 5914 secure udp/ip : 192.168.1.4:27015 (public ip: 135.120.128.85) map : gm_flatgrass at: 0 x, 0 y, 0 z players : 2 (16 max) # userid name uniqueid connected ping loss state adr # 2 "Chalu87" STEAM_0:1:70377242 05:01 35 0 active 192.168.1.4:27006 # 4 "Himatochi" STEAM_0:0:53654842 01:13 267 0 active 105.20.142.139:27005';
preg_match('~"' . preg_quote($user) . '"\s+(.*?)\s~', $data, $userid);
echo $userid[1];
Output:
STEAM_0:0:53654842
This searches for " username (with any special regex characters escaped) " then at least one white space. After the whitespace it captures everything until the next whitespace. The next whitespace character seemed like the easiest thing to match the end of the userid with.
If the format is consistent, you can get away with just using string functions, and that should be faster than envoking the complexity of the regex engine. You should run a quick benchmark to be sure though.
<?php
$str = 'hostname: Development Server version : 14.09.08/24 5914 secure udp/ip : 192.168.1.4:27015 (public ip: 135.120.128.85) map : gm_flatgrass at: 0 x, 0 y, 0 z players : 2 (16 max) # userid name uniqueid connected ping loss state adr # 2 "Chalu87" STEAM_0:1:70377242 05:01 35 0 active 192.168.1.4:27006 # 4 "Himatochi" STEAM_0:0:53654842 01:13 267 0 active 105.20.142.139:27005';
$user = 'Himatochi';
$user = '"' . $user . '"';
$str = substr(strrchr($str, $user), 2);
$userId = substr($str, 0, strpos($str, " "));
echo $userId;
Related
I have files which have contents that contain only "win" or "loss" like so:
win
win
loss
loss
loss
loss
win
loss
win
win
win
win
win
loss
loss
win
win
I would like to find the largest winning streak, which is the largest number of times that the word "win" has appeared on consecutive lines.
In the above example, "win" appears consecutively 2 , 1, 5 and 2 times.
so the largest win streak would be "5".
How can i use the Linux terminal or PHP to calculate this?
The only way i can think to do it is to look for "win" then use a large number of nested if statements to check the next line, but if the win streak was over 100+ then this would result in large amounts of code.
Is their examples of how this can be done more efficiently?
As there's still no PHP solution given to this question, and admittedly slightly more verbose than the solutions given in the comments... This might help:
<?php
$content = file_get_contents('winloss.txt');
$arr = explode("\r\n", $content);
$rep = repetition($arr);
echo $rep['response'];
function repetition(array $arr, $str1 = 'win', $str2 = 'loss')
{
$prevVal = null;
$count = 1;
foreach($arr as $key => $value) {
if($prevVal == $value) {
$count++;
$storeRep[$value][] = $count;
} else {
$count = 1;
}
$prevVal = $value;
}
$maxConsec[$str1] = max($storeRep[$str1]);
$maxConsec[$str2] = max($storeRep[$str2]);
$maxConsec['response'] = "largest winning streak : " . $maxConsec[$str1];
return $maxConsec;
}
output:
largest winning streak : 5
var_dump($rep):
array(3) {
["win"]=>
int(5)
["loss"]=>
int(4)
["response"]=>
string(26) "largest winning streak : 5"
}
$ uniq -c file | sort -rn | awk '$2=="win"{print $1; exit}'
5
You could do it all in awk of course:
awk '
$0!=prev { if (cnt > max[prev]) max[prev]=cnt; prev=$0; cnt=0 }
{ cnt++ }
END { if (cnt > max[prev]) max[prev]=cnt; print max["win"] }
' file
5
What surpises me, is that there also still is no pandas version. How is that possible?
import pandas
df= pd.read_csv('file.txt', names=['win_loss'], index_col=False)
df['group']=(df['win_loss'] != df['win_loss'].shift()).cumsum()
group_counts= df.groupby(df['group']).agg({'win_loss': 'first', 'group': 'count'}).groupby('win_loss').max()
print(group_counts.loc['win'])
As there still is not python version (which is a shame), I wanted to provide one:
fp= open('file.txt', 'rt')
oldline= None
line= fp.readline()
counts= dict()
currcount= 1
while line:
if line != oldline:
if oldline is not None and counts.get(oldline, 0) <= currcount:
counts[oldline]= currcount
currcount= 1
oldline= line
else:
currcount+= 1
line= fp.readline().strip()
print(counts['win'])
if counts.get(line, 0) <= currcount:
counts[line]= currcount
Btw, I would really love to know, how a python version performs in comparison to an awk version.
So now finally I can start with the COBOL version :-)
Here a version in COBOL. Slightly more verbose, than the other versions ;-)
You can simpy run it from a JCL in z/OS (loosely speaking: the bash version of z/OS):
IDENTIFICATION DIVISION.
PROGRAM-ID. WINCOUNT.
AUTHOR. JOTTBE.
*
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
*
SPECIAL-NAMES.
DECIMAL-POINT IS COMMA.
*
INPUT-OUTPUT SECTION.
FILE-CONTROL.
* ---CONTROL CARD
SELECT VCNT ASSIGN TO VCNT
ORGANIZATION SEQUENTIAL
ACCESS SEQUENTIAL
FILE STATUS VCNT-STATUS.
* ---INPUT FILE
SELECT CNT ASSIGN TO CNT
ORGANIZATION SEQUENTIAL
ACCESS SEQUENTIAL
FILE STATUS CNT-STATUS.
DATA DIVISION.
FILE SECTION.
* ---CONTROL CARD
FD VCNT
BLOCK CONTAINS 0 RECORDS
LABEL RECORD IS STANDARD
RECORDING MODE IS F.
01 VC-RECORD PIC X(080).
*----INPUT FILE
FD CNT
BLOCK CONTAINS 0 RECORDS
LABEL RECORD IS STANDARD
RECORDING MODE IS F.
01 C-RECORD PIC X(004).
WORKING-STORAGE SECTION.
01 PARMCARD.
* ---TEXT "SEARCH FOR: "
05 FILLER PIC X(012).
05 SEARCH-STRING PIC X(004).
05 FILLER PIC X(064).
01 INP-LINE.
05 STRING PIC X(004).
01 WORK.
05 LAST-STRING PIC X(004) VALUE " ".
05 LAST-COUNT PIC X(010) VALUE 0.
05 MAX-COUNT PIC X(010) VALUE 0.
01 K-CONSTANTS.
05 K-STATUS-OK PIC X(02) VALUE "00".
05 K-EOF PIC X(02) VALUE "10".
05 K-ERROR PIC X VALUE "E".
05 K-OK PIC X VALUE " ".
05 K-YES PIC X VALUE "Y".
01 S-SWITCHES.
05 S-PGM-STATUS PIC X VALUE " ".
05 S-ERROR PIC X VALUE " ".
05 S-END PIC X VALUE " ".
88 END-OF-PROCESSING VALUE "Y".
*
******************************************************************
PROCEDURE DIVISION.
******************************************************************
S00 SECTION.
INITIALIZE PARMCARD
INITIALIZE WORK
*
* ---OPEN FILES
*
* 1. PARAMETER CARD
OPEN INPUT VCNT
IF VCNT-STATUS = K-STATUS-OK
READ VCNT INTO PARMCARD
IF VCNT-STATUS = K-EOF
DISPLAY "ERROR OPENING THE PARAMETER CARD"
EXIT
END-IF
END-IF
* 2. INPUT FILE
OPEN INPUT CNT
IF CNT-STATUS = K-STATUS-OK
CONTINUE
ELSE
DISPLAY "ERROR OPENING THE INPUT FILE"
EXIT
END-IF
PERFORM UNTIL CNT-STATUS = K-EOF OR END-OF-PROCESSING
READ CNT INTO INP-LINE
AT END MOVE "Y" TO S-END
END-READ
IF STRING NOT = LAST-STRING
IF SEARCH-STRING = LAST-STRING
AND LAST-COUNT > MAX-COUNT
MOVE LAST-COUNT TO MAX-COUNT
END-IF
MOVE STRING TO LAST-STRING
MOVE 1 TO LAST-COUNT
END-IF
END-PERFORM
IF SEARCH-STRING = STRING
AND LAST-COUNT > MAX-COUNT
MOVE LAST-COUNT TO MAX-COUNT
END-IF
DISPLAY SEARCH-STRING " OCCURED " MAX-COUNT " TIMES."
EXIT.
Run it with a control card with the following content:
SEARCH FOR: WIN
Have fun.
I've got a complex directions URL and embed URL that I would like to get polylines for. Once I can get them into polylines or something similar I can convert to final format: GeoJSON.
Direction Link
-or-
Embed Link
I have looked at the API's and I can't find anything that accepts or would decode the PB (what is this? it's not a protocol buffer). So far this is as far as I've got:
//php
$pb_array = explode('!', $pb);
foreach($pb_array as $key => $value){
echo "$key - $value<br/>";
}
===
1 - 1m73
2 - 1m12
3 - 1m3
4 - 1d1472548.9575794793
5 - 2d-72.8191002664707
6 - 3d43.87505426780168
7 - 2m3
8 - 1f0
9 - 2f0
10 - 3f0
11 - 3m2
12 - 1i1024
13 - 2i768
14 - 4f13.1
15 - 4m58
16 - 3e0
17 - 4m5
18 - 1s0x0%3A0xa58b3d6041ba69f8
19 - 2sGuilford+Welcome+Center
20 - 3m2
21 - 1d42.8120069
22 - 2d-72.56614689999999
23 - 4m3
24 - 3m2
25 - 1d43.3893165
26 - 2d-72.40772249999999
27 - 4m5
28 - 1s0x4cb52e78df455c83%3A0xb6946ec850907db8
29 - 2s130+Lower+Michigan+Road%2C+Pittsfield%2C+VT+05762
30 - 3m2
31 - 1d43.76898
32 - 2d-72.815214
33 - 4m4
34 - 1s0x0%3A0xea2de48bba82cc86
35 - 3m2
36 - 1d44.042544
37 - 2d-72.6046997
38 - 4m5
39 - 1s0x0%3A0x6bb602ed58bf4413
40 - 2sJay+Peak+Resort
41 - 3m2
42 - 1d44.9379515
43 - 2d-72.5045433
44 - 4m5
45 - 1s0x4cb392aaa4333a07%3A0x160aef1559868340
46 - 2sDolly+Copp+Campground+Rd%2C+Gorham%2C+NH+03581
47 - 3m2
48 - 1d44.335842199999995
49 - 2d-71.21837339999999
50 - 4m5
51 - 1s0x4cb392684201a94d%3A0xfa4a6f490a05429d
52 - 2sMt+Washington+Auto+Road%2C+1+Mount+Washington+Auto+Road%2C+Gorham%2C+NH+03581
53 - 3m2
54 - 1d44.288384099999995
55 - 2d-71.22459599999999
56 - 4m5
57 - 1s0x4cb38e798f42c3d9%3A0xc3b88e4dac01db12
58 - 2sMt+Washington
59 - 3m2
60 - 1d44.270585399999995
61 - 2d-71.3032723
62 - 4m5
63 - 1s0x89e2a7fa444124d5%3A0xe3ed24b6f864eba0
64 - 2sWells%2C+ME
65 - 3m2
66 - 1d43.322232899999996
67 - 2d-70.5805209
68 - 4m5
69 - 1s0x89e2ba813e828c71%3A0x8cdf74380f6a933d
70 - 2sLibby's+Oceanside+Camp%2C+York+Street%2C+York%2C+ME
71 - 3m2
72 - 1d43.147162
73 - 2d-70.626173
74 - 5e1
75 - 3m2
76 - 1sen
77 - 2sus
78 - 4v1472497940601
The closest hints I could find are from this thread. I will keep looking but I'm stuck.
I'm trying to create an API based solution that has an input of one of these URL's and returns a GeoJSON.
would decode the PB (what is this? it's not a protocol buffer)
For the record, because this overflow question keeps popping up on google results: it is a protocol buffer. PB litteraly stands for protocol buffer.
It's just a different ASCII encoding (a compact URL encoding reminiscent of the binary encoding, not the usual JSON-like text encoding. When you squint at it it's not that much different than torrent's structure encoding), and Google doesn't provide us the .proto file.
For each field:
first character is the id (identifies the field according to the corresponding .proto file)
second character is the type of the field
m is for message
s is for string
i, j, u, v are for various type of ints
f, d are for floating points
e is for enum
the rest is the payload
So to unpack the fields you're seeing (even if we don't have the .proto file):
1m73 message of type 1, containing 73 elements (the whole message set)
1m12 submessage of type 1, contains 12 elements (probably information about the view box in the map box)
1m3 sub-sub-message type 1, contains 3 elements (probably map coordinates)
1d1472548.9575794793 first double field (probably zoom level)
2d-72.8191002664707 second double field (probably longitude)
3d43.87505426780168 third double field (probably latitude)
2m3 second sub-sub-sub message (no idea given that it's not filled. Maybe a starting point if you code a route instead of a single point ?)
1f0, 2f0, 3f0 the three members, currently just zero
3m2 third block (looks like a screen resolution)
1i1024, 2i768 : 1024x768 ? (and probably the omited field 3 would have been the color depth if present ??)
4f13.1 no idea, but it's a float
4m58 next message with 58 elements (to me it looks like a bunch of POI that we need to display in the box)
3e0 an enum, set to zero (this one would be completely impossible to interpret without a proto or without experimenting, as you need the list of enums)
4m5 five more elements probably a map poi
- 1s0x0%3A0xa58b3d6041ba69f8 string '0x0:0xa58b3d6041ba69f8', note the use of Url_encoded character. In turn it looks like a pair of hex numbers, maybe a GUID ?
- 2sGuilford+Welcome+Center string, the name with plus instead of blank (like most URLs)
- 3m2 two elements to come
- 1d42.8120069 and 2d-72.56614689999999 doubles probably map coordinates
4m3 again a message of type 4 in this level, so probably another poi
- 3m2, 1d43.3893165, 2d-72.40772249999999 but this one only specifies coordinates, and nothing else
4m5 another poi
- 1s0x4cb52e78df455c83%3A0xb6946ec850907db8 different pair of hex, GUID
...you got the idea...
5e1 another bunch of information probably general settings
3m2 this setting is a message (and looks like a locale)
1sen, 2sus locale is en_US
4v1472497940601 some other large number...
Note: the original proto that Google doesn't show us, is probably a single multi level structure. Thus, the sub-sub-message ID don't have always the same meaning: they aren't global ID, but ID within the parent message.
inside a sub message ID 1 (view box ?), the sub-sub message 3 seems to be resolution.
inside a sub message ID 4 (POIs ?), the sub-ID 3 isn't even a message but some enum
inside a sub message ID 5 (parameters), the sub-sub message 3 is a locale
Well, here's my sloppy but working solution. My needs required GeoJSON, but others can use the google maps service to get the desired output once you have the lat/lng array.
$embed = '<iframe src="https://www.google.com/maps/embed?pb=!1m73!1m12!1m3!1d1472548.9575794793!2d-72.8191002664707!3d43.87505426780168!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!4m58!3e0!4m5!1s0x0%3A0xa58b3d6041ba69f8!2sGuilford+Welcome+Center!3m2!1d42.8120069!2d-72.56614689999999!4m3!3m2!1d43.3893165!2d-72.40772249999999!4m5!1s0x4cb52e78df455c83%3A0xb6946ec850907db8!2s130+Lower+Michigan+Road%2C+Pittsfield%2C+VT+05762!3m2!1d43.76898!2d-72.815214!4m4!1s0x0%3A0xea2de48bba82cc86!3m2!1d44.042544!2d-72.6046997!4m5!1s0x0%3A0x6bb602ed58bf4413!2sJay+Peak+Resort!3m2!1d44.9379515!2d-72.5045433!4m5!1s0x4cb392aaa4333a07%3A0x160aef1559868340!2sDolly+Copp+Campground+Rd%2C+Gorham%2C+NH+03581!3m2!1d44.335842199999995!2d-71.21837339999999!4m5!1s0x4cb392684201a94d%3A0xfa4a6f490a05429d!2sMt+Washington+Auto+Road%2C+1+Mount+Washington+Auto+Road%2C+Gorham%2C+NH+03581!3m2!1d44.288384099999995!2d-71.22459599999999!4m5!1s0x4cb38e798f42c3d9%3A0xc3b88e4dac01db12!2sMt+Washington!3m2!1d44.270585399999995!2d-71.3032723!4m5!1s0x89e2a7fa444124d5%3A0xe3ed24b6f864eba0!2sWells%2C+ME!3m2!1d43.322232899999996!2d-70.5805209!4m5!1s0x89e2ba813e828c71%3A0x8cdf74380f6a933d!2sLibby's+Oceanside+Camp%2C+York+Street%2C+York%2C+ME!3m2!1d43.147162!2d-70.626173!5e1!3m2!1sen!2sus!4v1472497940601" width="600" height="450" frameborder="0" style="border:0" allowfullscreen></iframe>';
$array = array();
preg_match( '/src="([^"]*)"/i', $embed, $array ) ;
list($pre, $pb) = split("pb=", $array[1]);
if($pb == "" || strpos($pb, "!") === false)
die(json_encode(array("success"=>false)));
//echo "PB Extracted:<br>";
//echo $pb;
///echo "<br><br>Decode:<br/>";
$pb_array = explode('!', $pb);
$coords = array();
$address;$addressHex;
$results = array();
foreach($pb_array as $key => $value){
//uncomment to debug output
//echo "$key - $value<br/>";
if($value == "3m2" || $value == "2m2"){
//3m2 seems to be the divider of these 'places'
if(count($coords) != 3) //don't add the center of map data (3 coordinates [height, lng, lat])
array_push($results, array("coords"=>$coords,"address"=>$address,"addressHex"=>$addressHex));
$coords = array(); //reset array
}else{
$type = substr($value, 1, 1);
$stype = substr($value, 0, 2);
$value = substr($value, 2);
//echo "$type - $value<br/>";
if($type == "d"){
//Found Lat,Lng
array_push($coords, $value);
}else if($stype == "2s"){
//Address
$address = $value;
}else if($stype == "1s"){
//Address Encoded in some way
$addressHex = $value;
}
}
}
//echo "<br><br>Google Result<br/>";
//echo json_encode($results);
//echo "<br><br>Mapbox API:<br/>";
$waypoints = array();
for($i=0;$i<count($results);$i++){
if(count($results[$i]["coords"])){
$lat = $results[$i]["coords"][0];
$lng = $results[$i]["coords"][1];
array_push($waypoints, "$lng%2C$lat");
}
}
$waypoints = implode("%3B", $waypoints); //convert to string
$mapbox_api_key = "pk.eyJ1I.....";
$url = "https://api.mapbox.com/directions/v5/mapbox/driving/$waypoints.json?steps=false&alternatives=false&overview=full&geometries=geojson&access_token=$mapbox_api_key";
//echo "<br><br>Mapbox Response:<br/>";
$response = file_get_contents($url);
$json = json_decode($response,true);
//echo "<br><br>Mapbox Geometry:<br/>";
$coordinates = $json["routes"][0]["geometry"]["coordinates"];
$geojson = (array("type"=>"FeatureCollection","features"=>array(array("type"=>"Feature","geometry"=>array("type"=>"LineString","coordinates"=>$coordinates),"properties"=>array()))));
echo json_encode(array("success"=>true, "geojson"=>$geojson));
I have a text file in following format.
Wed Aug 27 20:24:53.536 IST
address ref clock st when poll reach delay offset disp
*~172.16.18.163 .GPS. 1 657 1024 377 13.99 1.801 19.630
~127.127.1.1 .LOCL. 3 15 64 377 0.00 0.000 1.920
* sys_peer, # selected, + candidate, - outlayer, x falseticker, ~ configured
file has been generated dynamically I need to fetch value of 'st' (1) value next to '.GPS.' . text '.GPS.' is going to be same in every file.
Check my following code:
$f1_content = file_get_contents('filename.txt');
if(preg_match("/\b(.*)\s(.*)\s[0-9]\s\b/i", $f1_content, $match))
{
print_r($match); die();
}
not getting any match. Any idea how it can be done?
You can follow this:
#\.GPS\.\s+\K(\d+)#is
PHP:
preg_match("#\.GPS\.\s+\K(\d+)#is", $f1_content, $match)
If you may have more than of occurrences of that, you should use preg_match_all
Live demo
(?=.*?\.GPS\.).*?GPS\.\s*(\d+)
Try this.This works.
See demo.
http://regex101.com/r/pP3pN1/12
for example, i recieved from POST ip and mask:
$ip = 2001:db8::1428:55ab;
$mask = 48;
and i want divide this subnet, i choose for example mask and how many subnets i want, for example $mask = 50, subnets = 2
and my result is (tree in a table), like this:
ip mask status
2001:db8::1428:55ab 48 divided
- 2001:db8::?????? 50 free
- 2001:db8::?????? 50 free
how can i do this? need help!
The $mask is actually the prefix-length. It is the number of bits that is 'fixed'. So a /48 prefix length means that the first 48 bits are fixed and the last (128 - 48 = ) 80 bits are available to be used.
In IPv6 a LAN always gets a /64. This means that with a /48 you get (64 - 48 = 16 bits. 216 = ) 65536 subnets.
IPv6 addresses and prefixes are written in hexadecimal. Each hexadecimal character is 4 bits. In IPv6 each group of numbers between : is 16 bits. Leading zeroes in each group can be omitted. So 2001:0db8:0000:0000:0000:0000:0000:0001 is the same as 2001:db8:0:0:0:0:0:1. The combination :: means that in that spot are only zeroes. So that address can also be written as2001:db8::1.
The information you give is a little confusing. You specify 2001:db8::1428:55ab/48. The problem is that you specify the last 32 bits of the IPv6 address (1428:55ab), while the mast specifies that those bits are not fixed. I will therefore use 2001:db8:1a2b::/48 as example.
Each increase in prefix length splits the previous prefix in two.
2001:db8:1a2b::/48 can be split into:
2001:db8:1a2b::/49
2001:db8:1a2b:8000::/49
2001:db8:1a2b::/49 can be split into:
2001:db8:1a2b::/50
2001:db8:1a2b:4000::/50
2001:db8:1a2b:8000::/49 can be split into:
2001:db8:1a2b:8000::/50
2001:db8:1a2b:c000::/50
Etc.
You could write it as a tree (just showing a few branches, I don't want to fill the page with the full 65536 subnets):
2001:0db8:1a2b:0000::/48
2001:0db8:1a2b:0000::/49
2001:0db8:1a2b:8000::/49
2001:0db8:1a2b:8000::/50
2001:0db8:1a2b:8000::/51
2001:0db8:1a2b:a000::/51
2001:0db8:1a2b:a000::/52
2001:0db8:1a2b:a000::/53
2001:0db8:1a2b:a800::/53
2001:0db8:1a2b:b000::/52
2001:0db8:1a2b:b000::/53
2001:0db8:1a2b:b800::/53
2001:0db8:1a2b:c000:/50
etc.
As you can see it's not that easy to read. It's easier if you subnet on multiples of 4 because then it matches the hexadecimal characters:
2001:0db8:1a2b:0000::/48
2001:0db8:1a2b:0000::/52
2001:0db8:1a2b:1000::/52
2001:0db8:1a2b:2000::/52
2001:0db8:1a2b:2000::/56
2001:0db8:1a2b:2000::/60
2001:0db8:1a2b:2000::/64
2001:0db8:1a2b:2001::/64
...
2001:0db8:1a2b:200f::/64
2001:0db8:1a2b:2010::/60
2001:0db8:1a2b:2010::/64
2001:0db8:1a2b:2011::/64
...
2001:0db8:1a2b:201f::/64
...
2001:0db8:1a2b:20f0::/60
2001:0db8:1a2b:3000::/52
etc.
You can use cidrl6 to split a /48 into four /50 subnets:
$ cidrl6 -s50 2001:db8::1428:55ab/48
2001:db8::/50
2001:db8:0:4000::/50
2001:db8:0:8000::/50
2001:db8:0:c000::/50
You could then read the output of this command into PHP as an array with something like exec().
<?php
$ip = "2001:db8::1428:55ab";
$mask = 48;
$subnet = 50;
$subnets = [];
exec("cidrl6 -s$subnet $ip/$mask", $subnets);
print_r($subnets);
Output:
Array
(
[0] => 2001:db8::/50
[1] => 2001:db8:0:4000::/50
[2] => 2001:db8:0:8000::/50
[3] => 2001:db8:0:c000::/50
)
I am doing this programming challenge which can be found at www.interviewstreet.com (its the first challenge worth 30 points).
When I submitted the solution, I was returned a result which said that the answer was wrong because it only passed 1/11 test cases. However, I feel have tested various cases and do not understand what I am doing wrong. It would be helpful to know what those test cases could be so that I can test my program.
Here is the question (in between the grey lines below):
Quadrant Queries (30 points)
There are N points in the plane. The ith point has coordinates (xi, yi). Perform the following queries:
1) Reflect all points between point i and j both including along the X axis. This query is represented as "X i j"
2) Reflect all points between point i and j both including along the Y axis. This query is represented as "Y i j"
3) Count how many points between point i and j both including lie in each of the 4 quadrants. This query is represented as "C i j"
Input:
The first line contains N, the number of points. N lines follow.
The ith line contains xi and yi separated by a space.
The next line contains Q the number of queries. The next Q lines contain one query each, of one of the above forms.
All indices are 1 indexed.
Output:
Output one line for each query of the type "C i j". The corresponding line contains 4 integers; the number of points having indices in the range [i..j] in the 1st,2nd,3rd and 4th quadrants respectively.
Constraints:
1 <= N <= 100000
1 <= Q <= 100000
You may assume that no point lies on the X or the Y axis.
All (xi,yi) will fit in a 32-bit signed integer
In all queries, 1 <=i <=j <=N
Sample Input:
4
1 1
-1 1
-1 -1
1 -1
5
C 1 4
X 2 4
C 3 4
Y 1 2
C 1 3
Sample Output:
1 1 1 1
1 1 0 0
0 2 0 1
Explanation:
When a query says "X i j", it means that take all the points between indices i and j both including and reflect those points along the X axis. The i and j here have nothing to do with the co-ordinates of the points. They are the indices. i refers to point i and j refers to point j
'C 1 4' asks you to 'Consider the set of points having index in {1,2,3,4}. Amongst those points, how many of them lie in the 1st,2nd,3rd and 4th quads respectively?'
The answer to this is clearly 1 1 1 1.
Next we reflect the points between indices '2 4' along the X axis. So the new coordinates are :
1 1
-1 -1
-1 1
1 1
Now 'C 3 4' is 'Consider the set of points having index in {3,4}. Amongst those points, how many of them lie in the 1st,2nd,3rd and 4th quads respectively?' Point 3 lies in quadrant 2 and point 4 lies in quadrant 1.
So the answer is 1 1 0 0
I'm coding in PHP and the method for testing is with STDIN and STDOUT.
Any ideas on difficult test cases to test my code with? I don't understand why I am failing 10 / 11 test cases.
Also, here is my code if you're interested:
// The global variable that will be changed
$points = array();
/******** Functions ********/
// This function returns the number of points in each quadrant.
function C($beg, $end) {
// $quad_count is a local array and not global as this gets reset for every C operation
$quad_count = array("I" => 0, "II" => 0, "III" => 0, "IV" => 0);
for($i=$beg; $i<$end+1; $i++) {
$quad = checkquad($i);
$quad_count[$quad]++;
}
return $quad_count["I"]." ".$quad_count["II"]." ".$quad_count["III"]." ".$quad_count["IV"];
}
// Reflecting over the x-axis means taking the negative value of y for all given points
function X($beg, $end) {
global $points;
for($i=$beg; $i<$end+1; $i++) {
$points[$i]["y"] = -1*($points[$i]["y"]);
}
}
// Reflecting over the y-axis means taking the negative value of x for all given points
function Y($beg, $end) {
global $points;
for($i=$beg; $i<$end+1; $i++) {
$points[$i]["x"] = -1*($points[$i]["x"]);
}
}
// Determines which quadrant a given point is in
function checkquad($i) {
global $points;
$x = $points[$i]["x"];
$y = $points[$i]["y"];
if ($x > 0) {
if ($y > 0) {
return "I";
} else {
return "IV";
}
} else {
if ($y > 0) {
return "II";
} else {
return "III";
}
}
}
// First, retrieve the number of points that will be provided. Make sure to check constraints.
$no_points = intval(fgets(STDIN));
if ($no_points > 100000) {
fwrite(STDOUT, "The number of points cannot be greater than 100,000!\n");
exit;
}
// Remember the points are 1 indexed so begin key from 1. Store all provided points in array format.
for($i=1; $i<$no_points+1; $i++) {
global $points;
list($x, $y) = explode(" ",fgets(STDIN)); // Get the string returned from the command line and convert to an array
$points[$i]["x"] = intval($x);
$points[$i]["y"] = intval($y);
}
// Retrieve the number of operations that will be provied. Make sure to check constraints.
$no_operations = intval(fgets(STDIN));
if($no_operations > 100000) {
fwrite(STDOUT, "The number of operations cannot be greater than 100,000!\n");
exit;
}
// Retrieve the operations, determine the type and send to the appropriate functions. Make sure i <= j.
for($i=0; $i<$no_operations; $i++) {
$operation = explode(" ",fgets(STDIN));
$type = $operation[0];
if($operation[1] > $operation[2]) {
fwrite(STDOUT, "Point j must be further in the sequence than point i!\n");
exit;
}
switch ($type) {
case "C":
$output[$i] = C($operation[1], $operation[2]);
break;
case "X":
X($operation[1], $operation[2]);
break;
case "Y":
Y($operation[1], $operation[2]);
break;
default:
$output[$i] = "Sorry, but we do not recognize this operation. Please try again!";
}
}
// Print the output as a string
foreach($output as $line) {
fwrite(STDOUT, $line."\n");
}
UPDATE:
I finally found a test case for which my program fails. Now I am trying to determine why. This is a good lesson on testing with large numbers.
10
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
12
C 1 10
X 1 3
C 5 5
Y 2 10
C 10 10
C 1 10
X 1 3
C 5 5
Y 2 10
C 10 10
X 3 7
C 9 9
I am going to test this properly by initializing an error array and determining which operations are causing an issue.
I discovered a test case that failed and understood why. I am posting this answer here so it's clear to everyone.
I placed a constraint on the program so that j must be greater than i, otherwise an error should be returned. I noticed an error with the following test case:
10
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1 1
1
C 2 10
The error returned for the operation C. Essentially the program believed that "2" was greater than "10". The reason for this I discovered was the following:
When using fgets(), a string is returned. If you perform string operations such as explode() or substr() on that line, you are converting the numbers in that initial string into a string again. So this means that the 10 becomes "10" and then after string operations becomes "0".
One solution to this is to use the sscanf() function and basically tell the program to expect a number. Example: for "C 2 10" you could use:
$operation_string = fgets(STDIN);
list($type, $begpoint, $endpoint) = sscanf($operation_string, "%s %d %d");
I submitted the new solution using sscanf() and now have 3/11 test cases passed. It did not check any more test cases because the CPU time limit was exceeded. So, now I have to go back and optimize my algorithm.
Back to work! :)
To answer, "What are those test cases?" Try this "solution":
<?php
$postdata = http_build_query(
array(
'log' => file_get_contents('php://stdin')
)
);
$opts = array('http' =>
array(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => $postdata
)
);
$context = stream_context_create($opts);
file_get_contents('http://myserver/answer.php', false, $context);
?>
On your server:
<?php
$fp = fopen('/tmp/answers.log', 'a');
fputs($fp, $_POST['log']."\n");
fclose($fp);
?>
Edit:
I did that. And came up with this being your main problem (I think):
$operation = explode(" ",fgets(STDIN));
Change that to:
$operation = explode(" ",trim(fgets(STDIN)));
Because otherwise "9" > "41 " due to string comparison. You should make that fix in any place you read a line.
As far as I guess, this solution won't work. Even if you solve the Wrong Answer problem, the solution will time out.
I was able to figure out a way for returning the quadrants count in O(1) time.
But not able to make the reflections in lesser time. :(