3
\$\begingroup\$

Consider this file path:

C:/Users/Martin/Desktop/BackupFiles/PC1/images/cars/new.png

Your goal is to write a program that will return the file path starting from the folder after the last folder that contains a number till the filename. So, for the above file path, the program should return images/cars/new.png.

One or more of the folder names may also contain spaces:

C:/Users/User1/Documents/Books/eBooks/PM2.4/ref/Project Management.pdf

should return ref/Project Management.pdf.

Also this filepath:

C:/Users/John/Videos/YouTube/3D/Animations/52.Tricky.Maneuvers/video234.png

should return video234.png.

Your answer should work with the above given three examples and all other examples that match the criteria described here.

This is , so the answer with the lowest number of bytes yields victory.

I am new to the site, so feel free to modify my post and/or add relevant tags.

\$\endgroup\$
15
  • 1
    \$\begingroup\$ @Stephen "challenge proposer". \$\endgroup\$
    – DELETE_ME
    Commented Sep 14, 2018 at 15:52
  • 3
    \$\begingroup\$ Do we have to support some weird Unicode characters like ߈ ("NKO DIGIT EIGHT") and would it be considered a number? \$\endgroup\$
    – DELETE_ME
    Commented Sep 14, 2018 at 16:00
  • 5
    \$\begingroup\$ I'm not clear on why the third test case is supposed to return Animations/52.Tricky.Maneuvers/video234.png as opposed to video234.png. Why does the folder 52.Tricky.Maneuvers not count as " the last folder that contains a number"? \$\endgroup\$
    – mypetlion
    Commented Sep 14, 2018 at 16:22
  • 2
    \$\begingroup\$ I agree with @mypetlion. 52.Tricky.Maneuvers contains a digit, so shouldn't it output video234.png instead? And if you mean by "starting from the folder after the last folder that contains a number till the filename" that there should always be at least one folder (regardless if it contains digits) before the file-path, doesn't that mean that C:\a1\a.pdf should output C:\a1\a.pdf?.. \$\endgroup\$ Commented Sep 14, 2018 at 16:52
  • 2
    \$\begingroup\$ As per the example given, you should start from the last folder that contains a number in its name.. This is not what your third example suggests. However, this is what your second example does. So, what's the correct one? \$\endgroup\$
    – DimChtz
    Commented Sep 14, 2018 at 17:16

17 Answers 17

7
\$\begingroup\$

JavaScript (ES6), 29 28 bytes

Saved 1 byte thanks to @tsh

s=>s.replace(/.*\d.*?\//,'')

Try it online!

How?

                                             /.*\d.*?\//
                                              \/\/\_/\/
                                              | |  | |
match the longest possible string (greedy) ---+ |  | |
match a digit ----------------------------------+  | |
match the shortest possible string (lazy) ---------+ |
match a slash ---------------------------------------+
\$\endgroup\$
2
  • \$\begingroup\$ So, why not s=>s.replace(/.*\d.*?\//,'')? \$\endgroup\$
    – tsh
    Commented Sep 16, 2018 at 8:18
  • \$\begingroup\$ @tsh Because I didn't realize it would be 1 byte shorter. :p Thanks! \$\endgroup\$
    – Arnauld
    Commented Sep 16, 2018 at 8:46
7
\$\begingroup\$

Gema, 8 bytes

*<D>*\/=

Sample run:

bash-4.4$ gema '*<D>*\/=' <<< 'C:/Users/Martin/Desktop/BackupFiles/PC1/images/cars/new.png'
images/cars/new.png

bash-4.4$ gema '*<D>*\/=' <<< 'C:/Users/User1/Documents/Books/eBooks/PM2.4/ref/Project Management.pdf'
ref/Project Management.pdf

bash-4.4$ gema '*<D>*\/=' <<< 'C:/Users/John/Videos/YouTube/3D/Animations/52.Tricky.Maneuvers/video234.png'
video234.png

Try it online!

\$\endgroup\$
4
  • \$\begingroup\$ Can you please add a Try It Online link? I am not familiar with Gema. \$\endgroup\$
    – Wais Kamal
    Commented Sep 17, 2018 at 14:24
  • \$\begingroup\$ Sorry, unfortunately there is no Gema or GeL interpreter on TIO. ☹ \$\endgroup\$
    – manatwork
    Commented Sep 17, 2018 at 14:28
  • \$\begingroup\$ Requested. \$\endgroup\$ Commented Sep 17, 2018 at 20:40
  • \$\begingroup\$ Might have better luck if you ask @pxeger to add it to ato.pxeger.com \$\endgroup\$
    – Jonah
    Commented Apr 2, 2022 at 17:06
4
\$\begingroup\$

sed, 17 bytes

s:.*[0-9][^/]*/::

Try it online.

\$\endgroup\$
4
\$\begingroup\$

05AB1E, 23 bytes

'/©¡RćUηí®ýʒþd_}®«õš¤X«

Try it online or verify all test cases.

05AB1E has no regexes, so this is not the kind of challenge it will do very good, in comparison to non-verbose languages that have a strength in regexes like Retina or Pyth.
Can probably still be golfed by at least a few bytes, though.

Explanation:

'/              # Push a "/"
  ©             # Store it in the register (without popping)
   ¡            # Split the (implicit) input on slashes
                #  i.e. "C:/Desktop3/Stuff/F0/images/new1.png"
                #   → ["C:","Desktop3","Stuff","F0","images","new1.png"]
    R           # Reverse this list
                #  i.e. ["C:","Desktop3","Stuff","F0","images","new1.png"]
                #   → ["new1.png","images","F0","Stuff","Desktop3","C:"]
     ć          # Head extracted
                #  i.e. ["new1.png","images","F0","Stuff","Desktop3","C:"]
                #   → ["images","F0","Stuff","Desktop3","C:"] and "new1.png"
      U         # Pop the extracted head, and store it in variable `X`
       η        # Take the prefixes of the list
                #  i.e. ["images","F0","Stuff","Desktop3","C:"]
                #   → [["images"],["images","F0"],["images","F0","Stuff"],["images","F0","Stuff","Desktop3"],["images","F0","Stuff","Desktop3","C:"]]
        í       # Reverse each inner list again
                #  i.e. [["images"],["images","F0"],["images","F0","Stuff"],["images","F0","Stuff","Desktop3"],["images","F0","Stuff","Desktop3","C:"]]
                #   → [["images"],["F0","images"],["Stuff","F0","images"],["Desktop3","Stuff","F0","images"],["C:","Desktop3","Stuff","F0","images"]]
         ®ý     # And join them by slashes
                #  i.e. [["images"],["F0","images"],["Stuff","F0","images"],["Desktop3","Stuff","F0","images"],["C:","Desktop3","Stuff","F0","images"]]
                #   → ["images","F0/images","Stuff/F0/images","Desktop3/Stuff/F0/images","C:/Desktop3/Stuff/F0/images"]
ʒ   }           # Now filter this list by:
 þ              #  Leave only the digits of this suffix
                #   i.e. "images" → ""
                #   i.e. "Stuff/F0/images" → 0
  d             #  Check if its >= 0
                #   i.e. "" → 0 (falsey)
                #   i.e. 0 → 1 (truthy)
   _            #  Inverse the boolean (0→1; 1→0)
     ®«         # Append a slash to each remaining suffix
                #  i.e. ["images"] → ["images/"]
       õš       # Prepend an empty string as list
                # (work-around when there are no valid suffices left)
                #  i.e. [] → [""]
                #  i.e. ["images/"] → ["","images/"]
         ¤      # Take the last suffix
                #  i.e. ["","images/"] → "images/"
          X«    # Append variable `X` (and implicitly output the result)
                #  i.e. "images/" and "new1.png" → "images/new1.png"
\$\endgroup\$
3
\$\begingroup\$

Powershell 42 39 45 30 26 bytes

Find the last decimal before a /, fetch all after the slash as the new path

($args-split'.*\d.*?/')[1]

Try it out!


- many bytes by tips from @mazzy
- 1 byte by removing non-required regex escape
- 4 bytes as the regex with -split didn't require a group
- added greedy decimal search

\$\endgroup\$
9
  • \$\begingroup\$ Great! I think $args is better then param($f)$f \$\endgroup\$
    – mazzy
    Commented Sep 14, 2018 at 18:15
  • 1
    \$\begingroup\$ Completely right, although using $args within an expression always seems to return the original value, powershell might think of it as an array with ToString() or something. Works fine with indexer though. \$\endgroup\$
    – Edwin
    Commented Sep 14, 2018 at 19:23
  • \$\begingroup\$ "$args". Welcome to Tips for golfing in PowerShell \$\endgroup\$
    – mazzy
    Commented Sep 14, 2018 at 21:07
  • \$\begingroup\$ The script return 2 values: $true/$false from -match expression and match string. I think should return the file path means the file path only. I beleave it can be golfed more. \$\endgroup\$
    – mazzy
    Commented Sep 14, 2018 at 21:11
  • 1
    \$\begingroup\$ split had a lot of additional perks :) \$\endgroup\$
    – Edwin
    Commented Sep 15, 2018 at 14:10
3
\$\begingroup\$

Ruby, 22 bytes

->s{s=~/.*\d.*?\//;$'}

Try it online!

Same trick as Arnauld and everybody else after him.

\$\endgroup\$
1
  • \$\begingroup\$ +1 for TIL about $' \$\endgroup\$
    – Jonah
    Commented Apr 2, 2022 at 17:21
3
\$\begingroup\$

Java (JDK 10), 26 bytes

s->s.split(".*\\d.*?/")[1]

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Retina, 9 bytes

.*\d.*?/

Regex is ported from @Arnauld's JavaScript answer, so make sure to upvote him!

Try it online.

Explanation:

.*\d.*?/    # Main regex:
.*          #  Zero or more characters (as much as possible)
  \d        #  Followed by a digit
    .*?     #  Followed by zero or more optional characters (as few as possible)
       /    #  Followed by a slash

            # Replace the match with:
            #  Nothing (so basically remove that leading part)
\$\endgroup\$
0
2
\$\begingroup\$

Jelly, 16 bytes

”/ɓṣṖf€ØDTṀ‘ṫ@ṣj

A monadic Link accepting a list of characters which returns a list of characters.

Try it online!

How?

”/ɓṣṖf€ØDTṀ‘ṫ@ṣj - Link: list of characters X
”/               - literal '/' character
  ɓ              - start a new dyadic chain with swapped arguments - i.e. f(X,'/')
   ṣ             - split (X) at ('/')
    Ṗ            - pop (removes the rightmost)
       ØD        - yield digit characters
      €          - for each: (of the parts of X after the split & pop)
     f           -   filter keep (digit characters)
         T       - truthy indices (1-indexed indices of parts containing any digit(s))
          Ṁ      - maximum (rightmost, zero if not found)
           ‘     - increment
              ṣ  - split (X) at ('/') (...again)
             @   - with swapped arguments:
            ṫ    -   tail (the split X) from index (the incremented maximum...)
               j - join with ('/')
\$\endgroup\$
2
\$\begingroup\$

Red, 79 bytes

func[s][d: charset"0123456789"parse s[any[to d thru"/"]copy t to end(print t)]]

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Python 2, 74 bytes

r='';k=1
for c in input():
 r+=c;k-=c.isdigit()
 if'/'==c:r*=k;k=1
print r

Try it online!


Python 2, 42 bytes

lambda n:re.sub(".*\d.*?/","",n)
import re

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Pyth, 14 bytes

The same regex solution that everybody else is using:

:z"^.*\d.*?/""

:                     regex replace
 z                    in the input() string
  "^.*\d.*?/"         the file path up until the last path with a number
             "        with an empty string (Pyth terminates this string at end of program)
\$\endgroup\$
2
\$\begingroup\$

Pip, 12 bytes

a@`\d.*?/`$'

Takes input as a command-line argument. Verify all test cases: Try it online!

Explanation

Does not use the same regex as everyone else! (Well, okay, it's pretty similar.)

a             1st command-line argument
  `\d.*?/`    Regex matching a digit, as few characters as possible, and then a slash
 @            Find all matches
          $'  Special variable: the portion of the string after the last match
              Autoprint

The shortest solutions using the standard regex were all 13 bytes:

aRM`.*\d.*?/`   Remove
a|>`.*\d.*?/`   Left-strip
aR`.*\d.*?/`x   Replace with empty string
\$\endgroup\$
1
\$\begingroup\$

Matlab, 68 bytes

function[r]=f(s),[~,b]=regexp(s,'/[^/;]+\d[^/;]+/');r=s(b+1:end);end

Try it Online!

\$\endgroup\$
1
  • \$\begingroup\$ disp(f('C:/Users/John/Videos/YouTube/3D/Animations/52/video234.png')); output an empty string due to + in regex. \$\endgroup\$
    – user111777
    Commented Apr 2, 2022 at 16:28
1
\$\begingroup\$

PHP 4 (42 chars)

Given $argv[1], it will silence the end's “Only variables should be passed by reference” notice.

echo@end(preg_split(';\d.*?/;',$argv[1]));
\$\endgroup\$
1
\$\begingroup\$

C, 103 100 88 bytes

*a(b,l)char*b;{for(b+=l;!isdigit(*b);b--);for(;*b-47&&*b;b++);for(;*b-47;b--);return b;}

Try online!

-22 bytes thanks to @ceilingcat

Note: the function may have undefined behavior if the string doesn't contain a number and a "/" character!

Ungolfed version

*a(b,l)char*b; /* b:the string, l:the length of the string */
{
    for(b += l; !isdigit(*b); b--); /* start from the end of the string and decrement pointer until a number is found */
    for(; *b-47 && *b; b++); /*increment pointer until '/' (ascii value 47) is found*/
    for(; *b-47; b--); /* decrement pointer until '/' is found */
    return b;
}
\$\endgroup\$
1
0
\$\begingroup\$

Perl 5 -p, 13 bytes

12 bytes for code; +1 for -p switch

s!.*\d.*?/!!

Try it online!

I solemnly swear I came up with my own solution before reading other answers.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.