douyuqing_12345
douyuqing_12345
2016-02-08 18:51

试图在php中使字符串输出成为一个数组

已采纳

I'm running into an issue where I get a rather irregular string output from an RCON script on a server. When I send a command for returning players on a server, I get a string that looks like this:

rcon->get_players();

Players on server: [#] [IP Address]:[Port] [Ping] [GUID] [Name] -------------------------------------------------- 0 1.1.1.1:2 46 654321(OK) Player Name1 1 2.2.2.2:2 47 123456(OK) Player Name2 (2 players in total)

Here's what it looks like formatted if that helps:

Players on server: 
[#] [IP Address]:[Port] [Ping] [GUID] [Name] 
-------------------------------------------------- 
0 1.1.1.1:2 46 654321(OK) Player Name1 
1 2.2.2.2:2 47 123456(OK) Player Name2 
(2 players in total)

So the first 0 is their key id on the server (0-however many players), the second is their IP and PORT, the 47 is the ping, playerguid is their battleye guid, then their name inthe game, and then a total of the players returned.

However, it returns as one big string. I'm trying to figure out how to feed this into an array. So I get something like this:

array("id"=>"0", "Connection"=>"1.1.1.1:2", "ping"=>"46", "guid"=>"654321", "name"=>"Player Name1");

Any way I can achieve this, considering how irregular the output is? Having the headers in the string is throwing me off.

I followed Don't Panic's advice and it's close: UPDATED

echo "Player List:<br />";
$raw_players = $rcon->get_players();
$lines = explode("
", $raw_players);
$end = count($lines)-1;
$keys = array('id','connection','ping','guid','name');
$regex = '/(\d+)\s+([\d\.\:]+)\s+(\d+)\s+(\d+)\(OK\)\s+(.+)/';
for ($i=3; $i < $end; $i++) {
    echo($lines[$i]);
    preg_match($regex, $lines[$i], $matches);
    unset($matches[0]);
    echo(var_dump($matches));
    $players[] = array_combine($keys, $matches);
}

And I get:

Player List:
0 98.193.210.251:2304 47 e0b29e3c7122bda33b5391c22594c776(OK) Colin Fox
array (size=0)
  empty
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

3条回答

  • douke9379 douke9379 5年前

    First, explode based on newlines to get an array of each line.

    $lines = explode("
    ", $string);
    

    then you can construct a for loop excluding the header and footer like this:

    $end = count($lines) - 1; // this will exclude the last line
    for ($i=3; $i < $end; $i++) { // this will start at the fourth line
    

    inside the loop, you can use explode again, with space as the delimiter, to get an array for every line.

    $players[] = explode(' ', $lines[$i], 5);
    

    This should work, because it looks like all the values at the beginning of each line do not have spaces. The third argument (5) will prevent the player name from being split on space (if it contains a space) because it restricts the size of the array generated by explode to 5 elements.

    If you want the resulting array to have string keys, you can define an array of keys (before your loop):

    $keys = array('id', 'connection', 'ping', 'guid', 'name');
    

    And then use array_combine in your loop to create each player array.

    $players[] = array_combine($keys, explode(' ', $lines[$i], 5));
    

    With some new info about this string, it seems that some of the columns are separated by more than one space (and not the same number of spaces), so explode will not work for this. You can use a regular expression match in your loop instead.

    $keys = array('id', 'connection', 'ping', 'guid', 'name');
    $regex = '/(\d+)\s+([\d\.\:]+)\s+(\d+)\s+(\w+)\(OK\)\s+(.+)/';
    for ($i=3; $i < $end; $i++) {
        preg_match($regex, $lines[$i], $matches);
        unset($matches[0]);
        $players[] = array_combine($keys, $matches);
    }
    

    The unset($matches[0]); is because the first element in the preg_match matches will be the entire string. Each of the subsequent values in $matches will be the contents of the capture groups. Here is an explanation of the regex:

    /            begin pattern
    (\d+)        capture one or more digits (id)
    \s+          skip one or more spaces
    ([\d\.\:]+)  capture one or more characters either digit, dot, or colon (ip/port)
    \s+          skip one or more spaces
    (\d+)        capture one or more digits (ping)
    \s+          skip one or more spaces
    (\w+)        capture one or more alphanumeric characters (guid)
    \(OK\)\s+    skip the (OK) and one or more spaces
    (.+)         capture everything else (player name)
    /            end pattern
    
    点赞 评论 复制链接分享
  • dongpiansui8755 dongpiansui8755 5年前

    I would use a regular expression on that, that looks like this:

    (\d+) ([\d.:]+) (\d+) (\d+)\([^)]+\) (.*)
    

    combined with preg_match_all in PHP like that:

    preg_match_all('#(\d+) ([\d.:]+) (\d+) (\d+)\([^)]+\) (.*)#', $players, $matches);
    
    点赞 评论 复制链接分享
  • dongzhuang5741 dongzhuang5741 5年前

    You could easily use the explode() function on the string using the spaces as delimiters. From there just only use the second half of the array.

    Alternatively use explode(), but set a limit such that the final element in the array can then be broken up into a second array.

    点赞 评论 复制链接分享