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:
- keep the file name
- keep the drive letter
- 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))