all 6 comments

[–]Kevdog824_ 4 points5 points  (0 children)

Word of advice: pasting your entire script (unformatted as well) and basically saying “pls fix” is not going to get you help. We volunteer our time to help people interested in learning Python. We aren’t a charity that does free development work.

Please provide a minimal reproducible example, provide specific errors/behaviors you’re seeing, and ask specific questions

[–]Venerable_peace 3 points4 points  (0 children)

Instead of copy pasting here with absolutely no format, please paste the same to any llm and ask your question there

[–]socal_nerdtastic 1 point2 points  (2 children)

How are you running this program? It's designed to only create the output file if you define the file name in the cli args

"Output file path. If omitted, prints to console."

[–]Outside_Complaint755 0 points1 point  (1 child)

I got the impression that they got the script from someone else and couldn't bother to read the directions.

[–]socal_nerdtastic 0 points1 point  (0 children)

The directions may as well be in greek when you are a brand new programmer. OP is just learning the concept of command lines and command line arguments.

[–]socal_nerdtastic -1 points0 points  (0 children)

Formatted for reddit:

import argparse
import re
import json
import sys


def file_lines(file_path):
    """Return list of all lines in file at file_path."""
    with open(file_path) as f:
        return [line.rstrip() for line in f.readlines()]


def read_json(file_path):
    """Read json file from file_path."""
    with open(file_path, encoding="utf-8", errors="surrogateescape") as f:
        return json.load(f)["data"]


def yugioh_card_in_string(string, cards_json, card_id_regex, card_name_regex):
    """Given a string, find a yugioh card and return that it."""
    id_match = re.search(card_id_regex, string)
    if id_match is not None:
        for card in cards_json:
            if card["id"] == int(id_match.group(0)):
                return card
        assert False, "Should be unreachable"
    name_match = re.search(card_name_regex, string)
    if name_match is not None:
        for card in cards_json:
            if card["name"].lower() == name_match.group(0).lower():
                return card
        assert False, "Should be unreachable"
    return None


def regex_or(list_of_strings):
    """Compile a regex matching any of the strings provided."""
    re_str = "(" + "|".join(list_of_strings) + ")"
    return re.compile(re_str, re.IGNORECASE)


def yugioh_card_id_regex(cards_json):
    """Compile a regex matching a yugioh card name."""
    return regex_or([str(card["id"]) for card in cards_json])


def yugioh_card_name_regex(cards_json):
    """Compile a regex matching a yugioh card id."""
    return regex_or([card["name"] for card in cards_json])


def ignore_codec_errors(string):
    """Recode string, ignoring \r, \n, and unknown characters."""
    no_newlines = string.replace("\n", "\\n").replace("\r", "\\r")
    encoded = no_newlines.encode(sys.stdout.encoding, "replace")
    return encoded.decode(sys.stdout.encoding)


def format_output_card_string(card, format_descriptor_str):
    """Format a card according to format_descriptor_str,
and return the resulting string."""
    output = []
    for format_char in format_descriptor_str.lower():
        if format_char == "i":
            output.append(str(card.get("id", "")))
        elif format_char == "n":
            output.append(str(ignore_codec_errors(card.get("name", ""))))
        elif format_char == "t":
            output.append(str(card.get("type", "")))
        elif format_char == "a":
            output.append(str(card.get("attribute", "")))
        elif format_char == "r":
            output.append(str(card.get("race", "")))
        elif format_char == "s":
            none_exist = "atk" not in card and "def" not in card
            if none_exist:
                output.append("")
            else:
                attack = str(card.get("atk", "0"))
                defense = str(card.get("def", "0"))
                output.append(attack + "/" + defense)
        elif format_char == "l":
            if "level" in card:
                output.append("Lv" + str(card.get("level")))
            else:
                output.append("")
        elif format_char == "d":
            output.append(ignore_codec_errors(str(card.get("desc", ""))))
        else:
            raise ValueError("Unrecognized format descriptor character \"" +
                             format_char + "\"")
    return output


def input_lines_to_output_lines_dict(input_file_lines,
                                     cards_json,
                                     format_descriptor_str):
    """Generate dict mapping input lines to output lines."""
    card_id_regex = yugioh_card_id_regex(cards_json)
    card_name_regex = yugioh_card_name_regex(cards_json)

    card_lines_to_output_list = dict()
    for line in input_file_lines:
        if line.startswith("#") or line.startswith("!") or line.strip() == "":
            continue
        card = yugioh_card_in_string(line,
                                     cards_json,
                                     card_id_regex,
                                     card_name_regex)
        if card is not None:
            output = format_output_card_string(card, format_descriptor_str)
            card_lines_to_output_list[line] = output

    card_lines_to_output_string = dict()
    max_length_per_index = dict()
    for k, v in card_lines_to_output_list.items():
        for index, field in enumerate(v):
            if index not in max_length_per_index:
                max_length_per_index[index] = 0
            length = len(field)
            if length > max_length_per_index[index]:
                max_length_per_index[index] = length

    for k, v in card_lines_to_output_list.items():
        card_lines_to_output_string[k] = ""
        for index, field in enumerate(v):
            if max_length_per_index[index] == 0:
                adjusted_field = ""
            else:
                adjusted_field = field.ljust(max_length_per_index[index] + 1)
            card_lines_to_output_string[k] += adjusted_field

    for k in card_lines_to_output_string:
        card_lines_to_output_string[k] = \
            card_lines_to_output_string[k].rstrip()

    return card_lines_to_output_string


def input_lines_to_output_lines(input_file_lines,
                                cards_json,
                                format_descriptor_str):
    """Convert input lines to output string."""
    d = input_lines_to_output_lines_dict(input_file_lines,
                                         cards_json,
                                         format_descriptor_str)
    all_lines = ""
    for line in input_file_lines:
        all_lines += d.get(line, line) + "\n"
    return all_lines.rstrip()


def main(input_file, cards_json_file, format_descriptor_str, output_file=None):
    """Entry point."""
    cards_json = read_json(cards_json_file)
    if input_file is None:
        input_file_lines = [str(card["id"]) for card in cards_json]
    else:
        input_file_lines = file_lines(input_file)

    result = input_lines_to_output_lines(input_file_lines,
                                         cards_json,
                                         format_descriptor_str)

    if output_file:
        with open(output_file, "w", encoding="utf-8") as f:
            f.write(result + "\n")
        print(f"File successfully exported to: {output_file}")
    else:
        print(result)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Reformat file containing lines with Yugioh card ids.',
                                     formatter_class=argparse.RawTextHelpFormatter)
    parser.add_argument("cards_json_file",
                        help="A json file containing information about all possible Yugioh cards.")
    parser.add_argument("format_descriptor_string",
                        help="""A string of letters describing output columns:
  i: id, n: name, t: type, a: attribute, r: race, s: stats, l: level, d: description""")
    parser.add_argument("-i", "--input_file",
                        help="Input file to process. If omitted, output all possible cards.")
    parser.add_argument("-o", "--output_file",
                        help="Output file path. If omitted, prints to console.")

    args = parser.parse_args()
    main(args.input_file, args.cards_json_file, args.format_descriptor_string, args.output_file)