def _splitter(
        self,
        *,
        func: Callable,
        pre: bool,
        dim: Hashable,
        sep: str | bytes | Any | None,
        maxsplit: int,
    ) -> DataArray:
        """
        Implements logic for `split` and `rsplit`.
        """
        if sep is not None:
            sep = self._stringify(sep)

        if dim is None:
            f_none = lambda x, isep: func(x, isep, maxsplit)
            return self._apply(func=f_none, func_args=(sep,), dtype=np.object_)

        # _apply breaks on an empty array in this case
        if not self._obj.size:
            return self._obj.copy().expand_dims({dim: 0}, axis=-1)

        f_count = lambda x, isep: max(len(func(x, isep, maxsplit)), 1)
        maxsplit = (
            self._apply(func=f_count, func_args=(sep,), dtype=np.int_).max().data.item()
            - 1
        )

        def _dosplit(mystr, sep, maxsplit=maxsplit, dtype=self._obj.dtype):
            res = func(mystr, sep, maxsplit)
            if len(res) < maxsplit + 1:
                pad = [""] * (maxsplit + 1 - len(res))
                if pre:
                    res += pad
                else:
                    res = pad + res
            return np.array(res, dtype=dtype)

        # dtype MUST be object or strings can be truncated
        # See: https://github.com/numpy/numpy/issues/8352
        return duck_array_ops.astype(
            self._apply(
                func=_dosplit,
                func_args=(sep,),
                dtype=np.object_,
                output_core_dims=[[dim]],
                output_sizes={dim: maxsplit},
            ),
            self._obj.dtype.kind,
        )

        Implements logic for `split` and `rsplit`.
        
xarray/core/accessor_str.py