1
\$\begingroup\$

I'm pretty sure the code is of mild quality but not entirely sure as I'm not much of a JavaScript programmer. Everything works as expected. A quick rundown of the code. It simply parses a string and builds some game data for saving into a database. One thing I'm not sure of is how I should handle data that doesn't conform to how it's expected.

// var diplo = `!report Game Type: Diplo Early Bird
// 1: <@12321321421412421>
// 2: <@23423052352342334>
// 3: <@45346346345343453>
// 4: <@23423423423523523>`

var diplo = `!report Game Type: Team Modded
Team: 1
    <@23452342359234534>
    <@34642342359232352>
Team: 2
    <@34534342359234879>
    <@58493457202345054>`


var report = {};


function gameType(game) {
    let data = {};
    let game_types = [{id: 1, name: 'Diplo'}, {id: 2, name: 'Always War'}, {id: 3, name: 'FFA'}
        , {id: 4, name: 'No Diplo'}, {id: 5, name: 'Team'}, {id: 6, name: 'Duel'}, {id: 7, name: 'No War'}];
    let o = {}
    let reType = /!report Game Type:[\s+]?(\d|\w+)\s?(\w+\s?(\w+)?)?\n/gi
    let match = reType.exec(game)
    if(match[1]){
        for (var j = 0; j < game_types.length; j++) {
            if ((game_types[j].name).toLowerCase() === (match[1]).toLowerCase()) {
                data.type = game_types[j].id;
                break;
            }
        }
    }
    if(match[2]){
        data.moddifier = match[2]
    }
    diplo = game.slice(reType.lastIndex);
    return (data)
}

function getPlayers(game) {
    let players = [];
    rePlayer = /(\d+):\s?<@(\d+)>[\s\S]?(\w+\s?\w+)?/gi;
        do {
            let o = {};
            player = rePlayer.exec(game);
            if (player) {
                o.position = player[1]
                o.discord_id = player[2]
                players.push(o);
            }
        } while (player);
        return players;
}

function getTeamPlayers(game) {
    let players = [];
    reTeam = /Team:\s(\d)[\s\S](\s+?<@(\d+)>)+/gi;
    rePlayer = /\s+?<@(\d+)>/gi;
    let i = 1;
    do {
        team = reTeam.exec(game);
        if(team){
            do {
                player = rePlayer.exec(team[0]);
                if(player){         
                    let o = {}; 
                    o.team_id = i;
                    o.position = team[1];
                    o.discord_id = player[1];
                    players.push(o);
                }
            }while(player)
        }
        i++;
    }while(team)
    return players;
}

function main() {

    console.log("Reading game data...")
    try {
        report = gameType(diplo)
        if(report.type === 5){
            report.players = getTeamPlayers(diplo);
        }else{
            report.players = getPlayers(diplo);
        }
        console.log(report)
    } catch (err) {
        return 'Error Processing Report!';
    }        
}

main();
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

I would manipulate RegExp.lastIndex with the sticky flag to avoid slicing the source string:

function parseGame(text) {
  const RX_HEADER = /!report Game Type:\s*(\d|\w+)(?:\s*(\w.*))?/y;
  const RX_TEAM = /Team:\s*(\d+)/y;
  const RX_DISCORD = /<@(\d+)>/y;
  const RX_POSITION_DISCORD = /(\d+):\s*<@(\d+)>\s*(?:\w+\s?\w+)?/y;
  const RX_WHITESPACE = /\s+/y;

  let pos = 0;
  const data = {players: []};

  function match(rx) {
    rx.lastIndex = pos;
    const matches = rx.exec(text);
    if (!matches) {
      return [];
    }
    pos = rx.lastIndex;
    if (pos < text.length) {
      RX_WHITESPACE.lastIndex = pos;
      RX_WHITESPACE.exec(text);
      pos = RX_WHITESPACE.lastIndex || pos;
    }
    return matches;
  }

  function readHeader() {
    const ID_NAME_MAP = {
      1: 'Diplo',
      2: 'Always War',
      3: 'FFA',
      4: 'No Diplo',
      5: 'Team',
      6: 'Duel',
      7: 'No War',
    };
    let [_, gameType, gameMod] = match(RX_HEADER);
    if (!gameType) {
      return;
    }
    gameType = gameType.toLowerCase();
    for (const type in ID_NAME_MAP) {
      if (type === gameType || ID_NAME_MAP[type].toLowerCase() === gameType) {
        data.type = Number(type);
        break;
      }
    }
    if (gameMod) {
      data.moddifier = gameMod;
    }
  }

  function readTeams() {
    let teamId;
    while ((teamId = Number(match(RX_TEAM)[1]))) {
      let position = 0;
      let discordId;
      while ((discordId = match(RX_DISCORD)[1])) {
        data.players.push({
          teamId,
          discordId,
          position: ++position,
        });
      }
    }
  }

  function readPlayers() {
    while (true) {
      const [_, position, discordId] = match(RX_POSITION_DISCORD);
      if (position) {
        data.players.push({
          discordId,
          position: Number(position),
        });
      } else {
        break;
      }
    }
  }

  readHeader();
  if (data.type === 5) {
    readTeams();
  } else {
    readPlayers();
  }
  return data;
}

And just to nitpick:

  • [\s+]? matches whitespace and a + which seems weird so I replaced it with \s*
  • [\s\S]? in rePlayer is ambiguous as it allows any single character, which seems weird.
    I would expect only whitespace and new line(s) allowed e.g. \s*
  • I usually specify a match group is unused via ?: e.g. (?:foo)?
  • Indent the code consistently
  • Consistently use spaces before opening braces e.g. if (foo) { instead of if(foo){
  • No need for var generally if you use ES6 anyway
  • Use const for variables you don't reassign (more info)
  • Use a consistent type for the id and position instead of mixing strings & numbers
  • Use a JS linter like eslint to catch the errors like a global player variable
  • Use camelCase for properties and variable names
  • Use object literals like arr.push({foo: 'bar'}) without an interim variable
\$\endgroup\$
2
  • \$\begingroup\$ Sweet, thanks for all the insight. Does the sticky flag, apply through different functions? \$\endgroup\$ Commented Sep 17, 2017 at 1:20
  • \$\begingroup\$ Yes, match and replace also respect lastIndex which is very handy in performance-critical code where you can do pos=str.indexOf('foo') first and then proceed with a complex regexp at the found position without slicing the string. \$\endgroup\$ Commented Sep 17, 2017 at 9:07

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.