class Laundromat {

    private static final String ESC_N_R_T_F = "[\\n\\r\\t\\f]";
    private static final String ESG_N_R_T_F_1_N = ESC_N_R_T_F + "+";

    /**
     * Sanitize {@code value} where it will be used in subsequent OpenGrok
     * (non-logging) processing.
     * @return {@code null} if null or else {@code value} with "pattern-breaking
     * characters" (tabs, CR, LF, FF) replaced as underscores (one for one)
     */
    public static String launderInput(String value) {
        return replaceAll(value, ESC_N_R_T_F, "_");
    }

    /**
     * Sanitize {@code value} where it will be used in a Lucene query.
     * @return {@code null} if null or else {@code value} with "pattern-breaking
     * characters" (tabs, CR, LF, FF) replaced as spaces. Contiguous matches are
     * replaced with one space.
     */
    public static String launderQuery(String value) {
        return replaceAll(value, ESG_N_R_T_F_1_N, " ");
    }

    /**
     * Sanitize {@code value} where it will be used in a log message only.
     * @return {@code null} if null or else {@code value} with "pattern-breaking
     * characters" tabs, CR, LF, and FF replaced as {@code "<TAB>"},
     * {@code "<CR>"}, {@code "<LF>"}, and {@code "<FF>"} resp.
     */
    public static String launderLog(String value) {<FILL_FUNCTION_BODY>}

    /**
     * Sanitize {@code map} where it will be used in a log message only.
     * @return  {@code map} with keys and values
     * sanitized with {@link #launderLog(String)}. If the sanitizing causes key
     * collisions, the colliding keys' values are combined.
     */
    @NotNull
    public static Map<String, String[]> launderLog(@Nullable Map<String, String[]> map) {

        return Optional.ofNullable(map)
                .stream()
                .map(Map::entrySet)
                .flatMap(Collection::stream)
                .sorted(Map.Entry.comparingByKey())
                .collect(Collectors.toMap(
                        entry -> launderLog(entry.getKey()),
                        entry -> launderLogArray(entry.getValue()),
                        Laundromat::mergeLogArrays
                ));
    }

    @NotNull
    private static String[] launderLogArray(@Nullable String[] values) {
        return Optional.ofNullable(values)
                .stream().flatMap(Arrays::stream)
                .map(Laundromat::launderLog)
                .toArray(String[]::new);
    }

    @NotNull
    private static String[] mergeLogArrays(@NotNull String[] existingSafeEntries,
                                           @NotNull String[] newSafeEntries) {
        return Stream.concat(Arrays.stream(newSafeEntries), Arrays.stream(existingSafeEntries))
                .toArray(String[]::new);

    }

    @Nullable
    private static String replaceAll(@Nullable String value, @NotNull String regex,
                                               @NotNull String replacement) {
        return Optional.ofNullable(value)
                .map(val -> val.replaceAll(regex, replacement))
                .orElse(null);
    }

    /* private to enforce static */
    private Laundromat() {
    }
}

        if (value == null) {
            return null;
        }
        return value.replace("\n", "<LF>").
                replace("\r", "<CR>").
                replace("\t", "<TAB>").
                replace("\f", "<FF>");
    
<no_super_class>