Home > Mobile >  Pretty printing of paths in python
Pretty printing of paths in python

Time:11-03

I want to know if there is a function in python that can pretty print a file path with a maximum number of characters

pretty_print("C:\Program Files\Common Files\Adobe\Keyfiles\dynamiclink\7.0\ConflictingP.xml",max_length=35)

output

C:\Program Files\...\ConflictingP.xml

conditions:

  1. keep the file name
  2. keep the drive letter
  3. truncate the leading folders to keep the string length less than or equal to the maximum length

CodePudding user response:

The short answer is no, there is no such path shortening function. There's a few details about how exactly you wanted this done that were missing, but here's a solution that I coded up for you:

import os, re

long_path="a/b/names/trying/to/write/long/path/name"

def shorten_path(input: str, max_length: int) -> str:
    if len(input)<max_length: return input # no need to shorten

    shortened_path = "..." # add middle item
    paths_to_choose_from = input.split(os.sep) # split by your custom OS separator. "/" for linux, "\" for windows.

    add_last_path = True
    while len(shortened_path)<max_length:
        if len(paths_to_choose_from) == 0: return shortened_path

        if add_last_path:
            shortened_path = shortened_path.replace("...", f"...{os.sep}{paths_to_choose_from[-1]}")
            del paths_to_choose_from[-1] # delete last elem
            add_last_path = False
        else:
            shortened_path = shortened_path.replace("...", f"{paths_to_choose_from[0]}{os.sep}...")
            del paths_to_choose_from[0] # delete last elem
            add_last_path = True
    return shortened_path

max_len = 17
print(shorten_path(long_path, max_len))
# >>> a/b/.../path/name

What this does is it splits the input path string by the OS separator, and then progressively adds items to the front and the back of the "...". It start adding the front-most path, and then adds the ones in the back. It continues this way until it exceeds the "max length". This function isn't too refined but hopefully it gives you some ideas of how this can be customized :)

CodePudding user response:

It's not that hard to implement yourself. In the next snippet I tried to prettify the path to make it look like C:\Program Files\C\A\K\d\7\ConflictingP.xml

from pathlib import PurePosixPath, PureWindowsPath

def pretty_print(path, max_length):
  # full folder names
  parts = PureWindowsPath(path).parts
  # only first letters
  short_parts = list(map(lambda part: part.lstrip()[0], parts))

  # since we show drive and file fully
  length_remaining = max_length - len(parts[0]) - len(parts[-1]) - 1 
  short_start = 1
  short_end = len(parts) - 1

  # try to fit as many full names as possible in the remaining length
  while short_start < short_end and len(parts[short_start]) < length_remaining:
      length_remaining -= len(parts[short_start]) - 1
      short_start  = 1

  # first print drive, then full names
  pretty = parts[0]   "\\".join(parts[1:short_start])
  # then short names (if needed)
  if short_end - short_start > 0:
    pretty  = "\\"   "\\".join(short_parts[short_start:short_end])
  # then file name
  return pretty   "\\"   parts[-1]

print(pretty_print("C:\\Program Files\\Common Files\\Adobe\\Keyfiles\\dynamiclink\\7.0\\ConflictingP.xml",max_length=35))

print(pretty_print("C:\\Program Files\\Common Files\\Adobe\\Keyfiles\\dynamiclink\\7.0\\ConflictingP.xml",max_length=55))

print(pretty_print("C:\\Program Files\\Common Files\\Adobe\\Keyfiles\\dynamiclink\\7.0\\ConflictingP.xml",max_length=155))

It prints

C:\Program Files\C\A\K\d\7\ConflictingP.xml
C:\Program Files\Common Files\Adobe\K\d\7\ConflictingP.xml
C:\Program Files\Common Files\Adobe\Keyfiles\dynamiclink\7.0\ConflictingP.xml

CodePudding user response:

May be something like this?

from pathlib import PurePath
import os

path = "a/b/names/trying/to/write/long/path/name"
parts = PurePath(path).parts

sep = os.sep
# Handle split Windows path on Linux
if len(parts) == 1:
  sep = "\\"
  parts = path.split(sep)
  
maxlen = 17

pretty_path = [parts[0]]
remaining = maxlen - len(parts[0]) - len(parts[-1]) - 1
for p in parts[1:]:
  if len(p) <= remaining - 1:
    pretty_path.append(p)
    remaining -= len(p) - 1
  else:
    while len(pretty_path) > 1 and remaining < 4:
      pretty_path.pop()
      
    pretty_path.append("...")
    break

pretty_path.append(parts[-1])

print(sep.join(pretty_path))
  • Related