Search code examples
stringrakuuppercaseletter

How does one manipulate the characters of a Raku string based on case?



In Raku, a given string is to be divided into its individual characters. Each character that is an uppercase letter is to be enclosed within angle brackets, and each other character is to be enclosed within single quotes. The resulting strings are to be joined together, separated by spaces.

Examples …

  • If the given string (without its delimiting quotation marks) were aSbTc, then the resulting string would be 'a' <S> 'b' <T> 'c' .
  • If the given string (without its delimiting quotation marks) were A BxyC$B, then the resulting string would be <A> ' ' <B> 'x' 'y' <C> '$' <B> .
  • If the given string (without its delimiting quotation marks) were XY12, then the resulting string would be <X> <Y> '1' '2' .

sub MAIN ( )
  {
  my $myString = 'aSbTc' ;
  # Desired output:  The string "'a' <S> 'b' <T> 'c'" (sans ").
  # Uppercase letters in angle brackets, each other character in single quotes.
  }


Update …

I have arrived at the following possible solution, but I suspect that there is a much more succinct (single-line?) solution …

sub delimited( $char )
  {
  if ( $char ~~ /<upper>/ )
    { '<' ~ $char ~ '>' }
  else
    { '\'' ~ $char ~ '\'' }
  }

sub toDelimitedString( $string )
  {
  my Seq $seq = $string.split( "", :skip-empty ) ;
  my Seq $delimitedSeq = map( &delimited, $seq ) ;
  my Str $result = $delimitedSeq.list.join: ' ' ;
  $result ;
  }

sub MAIN ( )
  {
  say toDelimitedString( 'aSbTc' ) ;     # OUTPUT: 'a' <S> 'b' <T> 'c'
  say toDelimitedString( 'A BxyC$B' ) ;  # OUTPUT: <A> ' ' <B> 'x' 'y' <C> '$' <B>
  say toDelimitedString( 'XY12' ) ;      # OUTPUT: <X> <Y> '1' '2'
  } # end sub MAIN


Solution

  • My oneliner solution would be:

    say "aSbTc".comb.map({ $_ ∈ "A".."Z" ?? "<$_>" !! "'$_'" }).join(" ")
    # 'a' <S> 'b' <T> 'c'
    

    Note that this only checks for the letters A through Z, which is not all capital letters. If you really want all capital letters:

    say "aSbTc".comb.map({ / <:Lu> / ?? "<$_>" !! "'$_'" }).join(" ")
    

    This uses a regular expression, which may or may not be more readable.