# Join strings with different delimiters and some possibly empty strings

I want to construct a string from several substrings, each one of those with a different delimiter. If the string is present, the delimiter and the string should be added, if not, none of them should be added.

This is my current code that looks a bit dirty to me:

def my_join(major, minor, patch=None, pre_release=None, build=None, revision=None):

version = '.'.join(filter(None,(major, minor, patch)))

if pre_release: version += '-%s'  % pre_release
if build:       version += '+b%s' % build
if revision:    version += '.%s'  % revision

return version

my_join('0', '1',pre_release='alpha')
'0.1-alpha'
my_join('2','3','4', build='567', revision='aabbcc440')
'2.3.4+b567.aabbcc440'


My problem is basically an extension of join 4 strings to the one if they are not empty in python with the addition of using different delimiter strings.

It doesn't look too bad to me; I'd make a few changes.

def my_join(major, minor, patch=None, prerelease=None,
build=None, revision=None):
version_parts = ['.'.join((major, minor, patch or ''))]

if prerelease:
version_parts.append('-%s' % prerelease)
if build:
version_parts.append('+b%s' % build)
if revision:
version_parts.append('.%s' % revision)

version = ''.join(version_parts)

return version


Instead of building the string piece-by-piece, this code adds the needed parts to a list which is then joined at the end. I also removed the overpowered call to filter, and instead used or to make the patch value be '' if patch is False-ish, as it would be if patch is None.

Your mileage may vary on whether this is an improvement but you can use the ternary operator:

version += '-%s'  % pre_release if pre_release else ''
version += '+b%s' % build if build else ''
version += '.%s'  % revision if revision else ''


I also think you should give a better name than my_join and add a docstring explaining your method.

def version_name(major, minor, patch=None, pre_release=None, build=None, revision=None):
"""When passed version details, will create a version name string."""


You didn't explain the intent so I might be misunderstanding the exact usage.

Opportunistic, but shorter way to do this:

import re
def format_version(major, minor, patch=None,
pre_release=None, build=None, revision=None):
return re.sub(r'(:?[\.-]|\+b)None', '',
'{major}.{minor}.{patch}-{pre_release}+b{build}.{revision}'
.format(**locals()))


This is opportunistic because it may fail in some "strange" situations, for example, if someone will literally pas the string 'None' as one of the arguments, however, I'd consider this to be too unlikely to be bothered with.

I'm not sure this makes it any better, but it does show one way to convert it to be a one line return:

def my_join(major, minor, patch=None, pre_release=None, build=None, revision=None):
return "%s%s%s%s" % (
'.'.join(filter(None,(major, minor, patch, pre_release))),
('-%s'  % pre_release) if pre_release else '',
('+b%s' % build) if build else '',
('.%s' % revision) if revision else '')


It does though remove the string concatenations.

• Hmm, I think string.format is a little more clear, but, that looks better – Quill Aug 27 '15 at 12:36