MediumStringsNot started

Hyphenate product codes

A warehouse label printer makes product codes easier to read by inserting a hyphen at every point where a letter is followed by a digit or a digit by a letter: AB12CD3 becomes AB-12-CD-3. Read product codes, one per line, until input ends, and print each code in its hyphenated form on its own line. Codes contain only uppercase letters and digits; a code with no switches is printed unchanged.

Input

One product code per line until end of input; each code has 1-50 characters, all uppercase letters or digits.

Output

One line per input code: the code with a hyphen inserted at every letter/digit boundary.

Example 1

Input

AB12CD3

Output

AB-12-CD-3

There are three boundaries: B|1, 2|C and D|3.

Example 2

Input

ZX90
4400Q
Q

Output

ZX-90
4400-Q
Q

The first code switches once, the second once, and the single-character code has no boundary at all.

Constraints

  • 1 <= number of codes <= 100
  • 1 <= length of each code <= 50
  • Codes contain only A-Z and 0-9

Hints

Hint 1 of 3

Iterate with code.chars() and build the result in a String with push.

Hint 2 of 3

Remember whether the previous character was a digit (c.is_ascii_digit()); when the current one differs, push a '-' before pushing the character.

Hint 3 of 3

There is no previous character at the start, so keep that memory as an Option<bool> that is None until the first character has been handled.

Solution

Show a reference solution and explanation
 Rust · reference solution
use std::io::{self, BufRead};

fn hyphenate(code: &str) -> String {
    let mut out = String::new();
    let mut prev_is_digit: Option<bool> = None;
    for c in code.chars() {
        let is_digit = c.is_ascii_digit();
        if let Some(prev) = prev_is_digit {
            if prev != is_digit {
                out.push('-');
            }
        }
        out.push(c);
        prev_is_digit = Some(is_digit);
    }
    out
}

fn main() {
    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let code = line.unwrap();
        let code = code.trim();
        if code.is_empty() {
            continue;
        }
        println!("{}", hyphenate(code));
    }
}

Why it works

Deciding whether to insert a hyphen needs exactly one piece of memory: was the previous character a digit? Keeping that as an Option<bool> makes the first iteration explicit instead of relying on a fake initial value, and if let Some(prev) skips the comparison exactly once. Building a fresh String with push is the idiomatic way to transform text in Rust, because a String is UTF-8 and cannot be indexed and modified byte by byte. is_ascii_digit is the right test here since the codes are ASCII; is_numeric would also accept digits from other scripts.

Lesson for this exercise: Control Flow in Rust: if, loop, while and for

Your program
use std::io::{self, BufRead};

fn hyphenate(code: &str) -> String {
    // walk the characters and insert '-' wherever a letter meets a digit
    code.to_string()
}

fn main() {
    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let code = line.unwrap();
        let code = code.trim();
        if code.is_empty() {
            continue;
        }
        println!("{}", hyphenate(code));
    }
}
Run is not available for Rust in the browser yet. Write your program here, then download it and run it locally with rustc 1.94 against the examples above. The reference solution below was verified the same way.

Tests: 6 cases including the examples. Passing every test marks the exercise solved in this browser.

How this page was checked. Every program on it was run with rustc 1.94 at build time by the publishing checks, and the output shown is what it printed. Running Rust inside the browser is not available yet, so the Run button is absent rather than pretending; copy the code and run it with rustc 1.94 locally.