Parsing SVG Path Data into Arrays Using Regex

SVG path data stored in the d attribute uses a condensed string format containing command letters and numerical coordinates. This article explains how to parse raw SVG path strings into structured mathematical arrays using regular expressions. By breaking down command types, capturing numerical tokens with regex, and converting them into numerical vectors, developers can extract coordinate matrices for geometric processing, custom rendering, physics calculations, and canvas animations.

Understanding SVG Path Data Syntax

An SVG path string consists of single-letter commands followed by coordinate parameters. For example:

M 10 20 L 30 40 C 50 60, 70 80, 90 100 Z

Parsing this data is challenging because the SVG specification allows several compact formatting shortcuts: * Whitespace and commas between numbers are optional if unambiguous (e.g., M10-20 means M 10 -20). * Consecutive decimal points can omit leading zeros and separators (e.g., L.5.5 means L 0.5 0.5). * Numbers can use scientific notation (e.g., 1e-4). * Subsequent coordinates after a command implicitly repeat that command.

The Regular Expression Strategy

To parse the string into discrete mathematical units, the process is split into two regex operations: 1. Command Segment Matching: Splitting the path string into individual command letters along with their trailing parameter strings. 2. Number Tokenization: Extracting floating-point numbers, integers, and exponential values from each parameter string.

1. Extracting Command Blocks

The regex below matches any command character (M, L, C, A, Z, etc., case-insensitive, excluding e which belongs to scientific notation) followed by its associated coordinate string:

const COMMAND_REGEX = /([a-df-z])([^a-df-z]*)/gi;

2. Extracting Coordinate Values

The number-parsing regex captures valid numerical values, including signs, decimals, and scientific notation:

const NUMBER_REGEX = /[-+]?(?:\d*\.\d+|\d+)(?:[eE][-+]?\d+)?/g;

Implementation: Converting Path Data to Arrays

The following JavaScript function parses an SVG path string into an array of objects or multi-dimensional numerical arrays.

function parseSVGPathToArrays(pathData) {
  const commandRegex = /([a-df-z])([^a-df-z]*)/gi;
  const numberRegex = /[-+]?(?:\d*\.\d+|\d+)(?:[eE][-+]?\d+)?/g;
  
  const parsedData = [];
  let match;

  while ((match = commandRegex.exec(pathData)) !== null) {
    const command = match[1];
    const rawNumbers = match[2].match(numberRegex);
    const coordinates = rawNumbers ? rawNumbers.map(Number) : [];

    parsedData.push({
      command: command,
      points: coordinates
    });
  }

  return parsedData;
}

Example Input and Output

Given the following input:

const path = "M0,0 L10.5,20.5 C30-40 50.2.8 100 200Z";
const result = parseSVGPathToArrays(path);

The returned structured array will be:

[
  { command: "M", points: [0, 0] },
  { command: "L", points: [10.5, 20.5] },
  { command: "C", points: [30, -40, 50.2, 0.8, 100, 200] },
  { command: "Z", points: [] }
]

Structuring into Coordinate Tuples

For mathematical calculations, flat parameter arrays can be grouped into coordinate pairs ([x, y] vectors) based on the command type:

function groupPoints(points, size = 2) {
  const groups = [];
  for (let i = 0; i < points.length; i += size) {
    groups.push(points.slice(i, i + size));
  }
  return groups;
}

function normalizePathToMatrix(parsedData) {
  return parsedData.map(item => {
    switch (item.command.toUpperCase()) {
      case 'M':
      case 'L':
      case 'T':
        return { command: item.command, vectors: groupPoints(item.points, 2) };
      case 'C':
        return { command: item.command, vectors: groupPoints(item.points, 2) }; // Control points + endpoint
      case 'Q':
      case 'S':
        return { command: item.command, vectors: groupPoints(item.points, 2) };
      case 'H':
      case 'V':
        return { command: item.command, vectors: item.points.map(v => [v]) };
      case 'A':
        // Arcs contain 7 parameters: [rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
        return { command: item.command, vectors: groupPoints(item.points, 7) };
      case 'Z':
        return { command: item.command, vectors: [] };
      default:
        return { command: item.command, vectors: groupPoints(item.points, 2) };
    }
  });
}

Handling Implicit Repeated Commands

In the SVG specification, if a command letter is followed by more coordinates than expected, the command repeats automatically: * Subsequent points after M (MoveTo) are treated as implicit L (LineTo) commands. * Subsequent points after other commands (like C or L) repeat that same command.

To handle this behavior, slice the extracted numbers according to the command’s parameter length and emit individual command arrays for each parameter set. This ensures consistent array dimensions for downstream linear algebra and transformation functions.