Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- TOON (Token-Oriented Object Notation) to indexed array code in Nodejs/python/C/golang.
- Usage:
- node toIndexedArray.js "employees[3]{id,name,department}: abc,John Doe,Engineering cdf,Jane Smith,Marketing fgz,Amy Zheng,IT"
- Output:
- [
- {
- "id": "abc",
- "name": "John Doe",
- "department": "Engineering"
- },
- {
- "id": "cdf",
- "name": "Jane Smith",
- "department": "Marketing"
- },
- {
- "id": "fgz",
- "name": "Amy Zheng",
- "department": "IT"
- }
- ]
- Nodejs:
- // toIndexedArray.js
- /**
- * Usage:
- * node toIndexedArray.js "employees[2]{id,name,dept}: 1,John,IT 2,Jane,HR"
- * node toIndexedArray.js "products[3]{code,title,price}: A001,Notebook,59.9 A002,Pen,129 A003,Eraser,15"
- *
- * Output: pure JSON array (indexed)
- */
- function convertToIndexedArray(input) {
- const inputTrim = input.trim();
- const colonPos = inputTrim.indexOf(':');
- if (colonPos === -1) {
- throw new Error('No colon found in input');
- }
- const header = inputTrim.substring(0, colonPos).trim();
- let dataString = inputTrim.substring(colonPos + 1).trim();
- const headerRegex = /^(\w+)\[\d+\]\{([^}]+)\}[::]?$/;
- const match = header.match(headerRegex);
- if (!match) {
- throw new Error('Invalid header format. Use: name[N]{field1,field2,...}');
- }
- const arrayName = match[1]; // Not used, but parsed for completeness
- const fields = match[2].split(',').map(f => f.trim());
- // Parse expected count from [N]
- const countMatch = header.match(/\[(\d+)\]/);
- const expectedCount = countMatch ? parseInt(countMatch[1], 10) : null;
- const firstFieldIsId = fields[0].toLowerCase() === 'id' || fields[0].toLowerCase().endsWith('id');
- let dataLines = [];
- if (dataString.includes('\n')) {
- // Multi-line mode
- dataLines = dataString.split('\n').map(l => l.trim()).filter(Boolean);
- } else {
- // Single-line mode
- const tokens = dataString.split(/\s+/).filter(t => t);
- dataLines = [];
- let i = 0;
- const numCommasNeeded = fields.length - 1;
- while (i < tokens.length) {
- let current = [tokens[i]];
- let currentStr = current[0];
- let commaCount = (currentStr.match(/,/g) || []).length;
- i++;
- while (commaCount < numCommasNeeded && i < tokens.length) {
- const nextToken = tokens[i];
- const tempStr = currentStr + ' ' + nextToken;
- const tempCount = (tempStr.match(/,/g) || []).length;
- if (tempCount > numCommasNeeded) {
- throw new Error(`Too many commas in row starting at ${current[0]}`);
- }
- current.push(nextToken);
- currentStr = tempStr;
- commaCount = tempCount;
- i++;
- }
- if (commaCount < numCommasNeeded) {
- throw new Error('Incomplete row');
- }
- // Add extra parts for last field if no comma in them
- while (i < tokens.length && !tokens[i].includes(',')) {
- const nextToken = tokens[i];
- current.push(nextToken);
- currentStr = currentStr + ' ' + nextToken;
- i++;
- }
- dataLines.push(currentStr);
- }
- }
- if (dataLines.length === 0) {
- throw new Error('No data rows found');
- }
- if (expectedCount !== null && dataLines.length !== expectedCount) {
- throw new Error(`Expected ${expectedCount} rows, but found ${dataLines.length}`);
- }
- const result = [];
- for (let i = 0; i < dataLines.length; i++) {
- const line = dataLines[i];
- const values = line.split(',').map(v => v.trim());
- if (values.length !== fields.length) {
- throw new Error(`Row ${i + 1} has ${values.length} values, but ${fields.length} fields are expected.`);
- }
- const obj = {};
- fields.forEach((field, idx) => {
- let value = values[idx];
- // Auto-convert "id" or fields ending with "Id" to number
- if (field.toLowerCase() === 'id' || field.toLowerCase().endsWith('id')) {
- const num = parseInt(value, 10);
- if (!isNaN(num)) value = num;
- }
- // Add more conversions if needed (e.g., parseFloat for 'price')
- obj[field] = value;
- });
- result.push(obj);
- }
- return result;
- }
- // Main
- if (process.argv.length < 3) {
- console.error('Usage: node toIndexedArray.js "your-text-here"');
- console.error('Example:');
- console.error(' node toIndexedArray.js "employees[2]{id,name,dept}: 1,Alice,IT 2,Bob,HR"');
- process.exit(1);
- }
- const inputText = process.argv.slice(2).join(' ');
- try {
- const array = convertToIndexedArray(inputText);
- console.log(JSON.stringify(array, null, 2));
- } catch (err) {
- console.error('Error:', err.message);
- process.exit(1);
- }
- Python:
- # to_indexed_array.py
- import sys
- import re
- import json
- def convert_to_indexed_array(input_str):
- input_trim = input_str.strip()
- colon_pos = input_trim.find(':')
- if colon_pos == -1:
- raise ValueError('No colon found in input')
- header = input_trim[:colon_pos].strip()
- data_string = input_trim[colon_pos + 1:].strip()
- header_regex = r'^(\w+)\[\d+\]\{([^}]+)\}[::]?$'
- match = re.match(header_regex, header)
- if not match:
- raise ValueError('Invalid header format. Use: name[N]{field1,field2,...}')
- array_name = match.group(1) # Not used
- fields = [f.strip() for f in match.group(2).split(',')]
- count_match = re.search(r'\[(\d+)\]', header)
- expected_count = int(count_match.group(1)) if count_match else None
- first_field_is_id = fields[0].lower() == 'id' or fields[0].lower().endswith('id')
- data_lines = []
- if '\n' in data_string:
- # Multi-line mode
- data_lines = [l.strip() for l in data_string.split('\n') if l.strip()]
- else:
- # Single-line mode
- tokens = re.split(r'\s+', data_string)
- tokens = [t for t in tokens if t]
- i = 0
- num_commas_needed = len(fields) - 1
- while i < len(tokens):
- current = [tokens[i]]
- current_str = current[0]
- comma_count = current_str.count(',')
- i += 1
- while comma_count < num_commas_needed and i < len(tokens):
- next_token = tokens[i]
- temp_str = current_str + ' ' + next_token
- temp_count = temp_str.count(',')
- if temp_count > num_commas_needed:
- raise ValueError(f'Too many commas in row starting at {current[0]}')
- current.append(next_token)
- current_str = temp_str
- comma_count = temp_count
- i += 1
- if comma_count < num_commas_needed:
- raise ValueError('Incomplete row')
- # Add extra parts for last field if no comma in them
- while i < len(tokens) and ',' not in tokens[i]:
- next_token = tokens[i]
- current.append(next_token)
- current_str += ' ' + next_token
- i += 1
- data_lines.append(current_str)
- if not data_lines:
- raise ValueError('No data rows found')
- if expected_count is not None and len(data_lines) != expected_count:
- raise ValueError(f'Expected {expected_count} rows, but found {len(data_lines)}')
- result = []
- for idx, line in enumerate(data_lines):
- values = [v.strip() for v in line.split(',')]
- if len(values) != len(fields):
- raise ValueError(f'Row {idx + 1} has {len(values)} values, but {len(fields)} fields are expected.')
- obj = {}
- for field, value in zip(fields, values):
- if field.lower() == 'id' or field.lower().endswith('id'):
- try:
- obj[field] = int(value)
- except ValueError:
- obj[field] = value
- else:
- obj[field] = value
- result.append(obj)
- return result
- if __name__ == "__main__":
- if len(sys.argv) < 2:
- print('Usage: python to_indexed_array.py "your-text-here"')
- print('Example:')
- print(' python to_indexed_array.py "employees[2]{id,name,dept}: 1,Alice,IT 2,Bob,HR"')
- sys.exit(1)
- input_text = ' '.join(sys.argv[1:])
- try:
- array = convert_to_indexed_array(input_text)
- print(json.dumps(array, indent=2, ensure_ascii=False))
- except ValueError as err:
- print('Error:', err)
- sys.exit(1)
- C:
- // to_indexed_array.c
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <regex.h>
- // Function to trim whitespace
- char* trim(char* str) {
- char* end;
- while (isspace((unsigned char)*str)) str++;
- if (*str == 0) return str;
- end = str + strlen(str) - 1;
- while (end > str && isspace((unsigned char)*end)) end--;
- end[1] = '\0';
- return str;
- }
- // Function to split string by delimiter
- int split(const char* str, char delim, char*** tokens) {
- int count = 0;
- char* temp = strdup(str);
- char* token = strtok(temp, &delim);
- while (token) {
- count++;
- token = strtok(NULL, &delim);
- }
- free(temp);
- *tokens = malloc(sizeof(char*) * count);
- temp = strdup(str);
- token = strtok(temp, &delim);
- int i = 0;
- while (token) {
- (*tokens)[i] = strdup(trim(token));
- token = strtok(NULL, &delim);
- i++;
- }
- free(temp);
- return count;
- }
- int main(int argc, char* argv[]) {
- if (argc < 2) {
- fprintf(stderr, "Usage: %s \"your-text-here\"\n", argv[0]);
- fprintf(stderr, "Example:\n");
- fprintf(stderr, " %s \"employees[2]{id,name,dept}: 1,Alice,IT 2,Bob,HR\"\n", argv[0]);
- return 1;
- }
- // Join all arguments into one string
- size_t len = 0;
- for (int i = 1; i < argc; i++) len += strlen(argv[i]) + 1;
- char* input_text = malloc(len);
- input_text[0] = '\0';
- for (int i = 1; i < argc; i++) {
- strcat(input_text, argv[i]);
- if (i < argc - 1) strcat(input_text, " ");
- }
- char* input_trim = trim(input_text);
- char* colon_pos = strchr(input_trim, ':');
- if (!colon_pos) {
- fprintf(stderr, "Error: No colon found in input\n");
- free(input_text);
- return 1;
- }
- *colon_pos = '\0';
- char* header = trim(input_trim);
- char* data_string = trim(colon_pos + 1);
- regex_t regex;
- regmatch_t matches[3];
- int reti = regcomp(®ex, "^(\\w+)\\[(\\d+)\\]\\{([^}]+)\\}[::]?$", REG_EXTENDED);
- if (reti) {
- fprintf(stderr, "Could not compile regex\n");
- free(input_text);
- return 1;
- }
- reti = regexec(®ex, header, 3, matches, 0);
- if (reti) {
- fprintf(stderr, "Error: Invalid header format. Use: name[N]{field1,field2,...}\n");
- regfree(®ex);
- free(input_text);
- return 1;
- }
- char* array_name = strndup(header + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
- char count_str[10];
- strncpy(count_str, header + matches[2].rm_so, matches[2].rm_eo - matches[2].rm_so);
- count_str[matches[2].rm_eo - matches[2].rm_so] = '\0';
- int expected_count = atoi(count_str);
- char* fields_str = strndup(header + matches[3].rm_so, matches[3].rm_eo - matches[3].rm_so);
- char** fields;
- int num_fields = split(fields_str, ',', &fields);
- regfree(®ex);
- free(fields_str);
- free(array_name);
- int first_field_is_id = (strcasecmp(fields[0], "id") == 0 || strncasecmp(fields[0] + strlen(fields[0]) - 2, "id", 2) == 0);
- char** data_lines = NULL;
- int num_lines = 0;
- char* newline_pos = strchr(data_string, '\n');
- if (newline_pos) {
- // Multi-line
- char** lines;
- num_lines = split(data_string, '\n', &lines);
- data_lines = malloc(sizeof(char*) * num_lines);
- for (int i = 0; i < num_lines; i++) {
- char* trimmed = trim(lines[i]);
- if (strlen(trimmed) > 0) {
- data_lines[num_lines++] = strdup(trimmed);
- }
- free(lines[i]);
- }
- free(lines);
- } else {
- // Single-line
- char** tokens;
- int num_tokens = split(data_string, ' ', &tokens);
- int i = 0;
- int num_commas_needed = num_fields - 1;
- while (i < num_tokens) {
- char* current = strdup(tokens[i]);
- int comma_count = 0;
- for (char* p = current; *p; p++) if (*p == ',') comma_count++;
- i++;
- while (comma_count < num_commas_needed && i < num_tokens) {
- char* temp = malloc(strlen(current) + strlen(tokens[i]) + 2);
- sprintf(temp, "%s %s", current, tokens[i]);
- free(current);
- current = temp;
- comma_count = 0;
- for (char* p = current; *p; p++) if (*p == ',') comma_count++;
- i++;
- }
- if (comma_count < num_commas_needed) {
- fprintf(stderr, "Error: Incomplete row\n");
- // Free memory
- for (int j = 0; j < num_tokens; j++) free(tokens[j]);
- free(tokens);
- for (int j = 0; j < num_fields; j++) free(fields[j]);
- free(fields);
- free(input_text);
- return 1;
- }
- while (i < num_tokens && strchr(tokens[i], ',') == NULL) {
- char* temp = malloc(strlen(current) + strlen(tokens[i]) + 2);
- sprintf(temp, "%s %s", current, tokens[i]);
- free(current);
- current = temp;
- i++;
- }
- data_lines = realloc(data_lines, sizeof(char*) * (num_lines + 1));
- data_lines[num_lines++] = current;
- }
- for (int j = 0; j < num_tokens; j++) free(tokens[j]);
- free(tokens);
- }
- if (num_lines == 0) {
- fprintf(stderr, "Error: No data rows found\n");
- // Free memory
- for (int j = 0; j < num_fields; j++) free(fields[j]);
- free(fields);
- free(input_text);
- return 1;
- }
- if (expected_count && num_lines != expected_count) {
- fprintf(stderr, "Error: Expected %d rows, but found %d\n", expected_count, num_lines);
- // Free memory
- for (int j = 0; j < num_lines; j++) free(data_lines[j]);
- free(data_lines);
- for (int j = 0; j < num_fields; j++) free(fields[j]);
- free(fields);
- free(input_text);
- return 1;
- }
- // Output JSON
- printf("[\n");
- for (int i = 0; i < num_lines; i++) {
- char** values;
- int num_values = split(data_lines[i], ',', &values);
- if (num_values != num_fields) {
- fprintf(stderr, "Error: Row %d has %d values, but %d fields are expected.\n", i + 1, num_values, num_fields);
- // Free memory
- for (int j = 0; j < num_values; j++) free(values[j]);
- free(values);
- for (int j = 0; j < num_lines; j++) free(data_lines[j]);
- free(data_lines);
- for (int j = 0; j < num_fields; j++) free(fields[j]);
- free(fields);
- free(input_text);
- return 1;
- }
- printf(" {\n");
- for (int j = 0; j < num_fields; j++) {
- char* value = values[j];
- int is_number = 0;
- if (strcasecmp(fields[j], "id") == 0 || strncasecmp(fields[j] + strlen(fields[j]) - 2, "id", 2) == 0) {
- char* endptr;
- strtol(value, &endptr, 10);
- if (*endptr == '\0') is_number = 1;
- }
- printf(" \"%s\": ", fields[j]);
- if (is_number) {
- printf("%s", value);
- } else {
- printf("\"%s\"", value);
- }
- if (j < num_fields - 1) printf(",");
- printf("\n");
- free(values[j]);
- }
- free(values);
- printf(" }");
- if (i < num_lines - 1) printf(",");
- printf("\n");
- free(data_lines[i]);
- }
- printf("]\n");
- free(data_lines);
- for (int j = 0; j < num_fields; j++) free(fields[j]);
- free(fields);
- free(input_text);
- return 0;
- }
- Golang:
- // to_indexed_array.go
- package main
- import (
- "fmt"
- "os"
- "regexp"
- "strconv"
- "strings"
- )
- func convertToIndexedArray(input string) ([]map[string]interface{}, error) {
- inputTrim := strings.TrimSpace(input)
- colonPos := strings.Index(inputTrim, ":")
- if colonPos == -1 {
- return nil, fmt.Errorf("no colon found in input")
- }
- header := strings.TrimSpace(inputTrim[:colonPos])
- dataString := strings.TrimSpace(inputTrim[colonPos+1:])
- headerRegex := regexp.MustCompile(`^(\w+)\[\d+\]\{([^}]+)\}[::]?$`)
- match := headerRegex.FindStringSubmatch(header)
- if match == nil {
- return nil, fmt.Errorf("invalid header format. Use: name[N]{field1,field2,...}")
- }
- // arrayName := match[1] // Not used
- fields := strings.Split(match[2], ",")
- for i := range fields {
- fields[i] = strings.TrimSpace(fields[i])
- }
- countRegex := regexp.MustCompile(`\[(\d+)\]`)
- countMatch := countRegex.FindStringSubmatch(header)
- var expectedCount *int
- if countMatch != nil {
- count, _ := strconv.Atoi(countMatch[1])
- expectedCount = &count
- }
- firstFieldIsID := strings.ToLower(fields[0]) == "id" || strings.HasSuffix(strings.ToLower(fields[0]), "id")
- var dataLines []string
- if strings.Contains(dataString, "\n") {
- // Multi-line mode
- lines := strings.Split(dataString, "\n")
- for _, l := range lines {
- trimmed := strings.TrimSpace(l)
- if trimmed != "" {
- dataLines = append(dataLines, trimmed)
- }
- }
- } else {
- // Single-line mode
- tokens := strings.Fields(dataString)
- i := 0
- numCommasNeeded := len(fields) - 1
- for i < len(tokens) {
- current := []string{tokens[i]}
- currentStr := current[0]
- commaCount := strings.Count(currentStr, ",")
- i++
- for commaCount < numCommasNeeded && i < len(tokens) {
- nextToken := tokens[i]
- tempStr := currentStr + " " + nextToken
- tempCount := strings.Count(tempStr, ",")
- if tempCount > numCommasNeeded {
- return nil, fmt.Errorf("too many commas in row starting at %s", current[0])
- }
- current = append(current, nextToken)
- currentStr = tempStr
- commaCount = tempCount
- i++
- }
- if commaCount < numCommasNeeded {
- return nil, fmt.Errorf("incomplete row")
- }
- // Add extra parts for last field if no comma in them
- for i < len(tokens) && !strings.Contains(tokens[i], ",") {
- nextToken := tokens[i]
- current = append(current, nextToken)
- currentStr += " " + nextToken
- i++
- }
- dataLines = append(dataLines, currentStr)
- }
- }
- if len(dataLines) == 0 {
- return nil, fmt.Errorf("no data rows found")
- }
- if expectedCount != nil && len(dataLines) != *expectedCount {
- return nil, fmt.Errorf("expected %d rows, but found %d", *expectedCount, len(dataLines))
- }
- result := []map[string]interface{}{}
- for idx, line := range dataLines {
- values := strings.Split(line, ",")
- for j := range values {
- values[j] = strings.TrimSpace(values[j])
- }
- if len(values) != len(fields) {
- return nil, fmt.Errorf("row %d has %d values, but %d fields are expected", idx+1, len(values), len(fields))
- }
- obj := map[string]interface{}{}
- for j, field := range fields {
- value := values[j]
- if strings.ToLower(field) == "id" || strings.HasSuffix(strings.ToLower(field), "id") {
- if num, err := strconv.Atoi(value); err == nil {
- obj[field] = num
- continue
- }
- }
- obj[field] = value
- }
- result = append(result, obj)
- }
- return result, nil
- }
- func main() {
- if len(os.Args) < 2 {
- fmt.Printf("Usage: %s \"your-text-here\"\n", os.Args[0])
- fmt.Println("Example:")
- fmt.Printf(" %s \"employees[2]{id,name,dept}: 1,Alice,IT 2,Bob,HR\"\n", os.Args[0])
- os.Exit(1)
- }
- inputText := strings.Join(os.Args[1:], " ")
- array, err := convertToIndexedArray(inputText)
- if err != nil {
- fmt.Println("Error:", err)
- os.Exit(1)
- }
- jsonBytes, err := json.MarshalIndent(array, "", " ")
- if err != nil {
- fmt.Println("Error marshaling JSON:", err)
- os.Exit(1)
- }
- fmt.Println(string(jsonBytes))
- }
Advertisement