Help Replacing Newline Characters

I want to replace newline/carriage returns from a column of numbers copied to the clipboard from a spreadsheet:

125429
125426
125429
125426

So that all but the last newline/carriage return is a colon:

125429:125426:125429:125426

Here is the macro that stubbornly refuses to replace the newline characters:

ReplaceNewLines

I have confirmed using UnicodeChecker that the character is U+000A. This pattern works in Patterns, just not in Keyboard Maestro.

Help!

Have you tried a simple "Search and Replace" rather than a regex?

image

Depending on the source of the text you may have to replace %LineFeed% with %Return%.

You can then either always, or conditionally, strip the last character to remove the trailing :

image

Otherwise you should post your actual macro (not an image of it) so people can check Action options, spot invisible characters, etc. Because your regex Replace seems to be working for me...

2 Likes

Row delimiters vary with their source and history.

Belt and braces, with split and rejoin, might look something like this:

Split rows rejoined with a delimiter.kmmacros (2.3 KB)

Expand disclosure triangle to view JS source
(() => {
    "use strict";

    // lines :: String -> [String]
    const lines = s =>
        // A list of strings derived from a single string
        // which is delimited by \n or by \r\n or \r.
        Boolean(s.length) ? (
            s.split(/\r\n|\n|\r/u)
        ) : [];

    return lines(
        Application("Keyboard Maestro Engine")
        .getvariable("sampleRows")
    )
    .join(":");
})();
2 Likes

Thanks ComplexPoint and Nige_S,

I went with the JavaScript option. I was trying to do regex the Keyboard Maestro way, but perhaps it is just easier to drop out into a scripting language.

For completeness, here are the two macros:


Create collection view.kmmacros (21.4 KB)

Macro-Image

image


Create collection view 2.kmmacros (22.0 KB)

Macro-Image

image


This may have been deliberate, but did you realise your regex had two lines?

\R(?=\d)
\r

Going from your screenshot, I was only using the first -- which is possibly why mine worked (and is certainly why you should always post a the actual troublesome macro and not just an image of it!).

1 Like

No I did not! I kept fiddling with the visible line. It never occurred to me this was a multiline field. Is this a bug or a feature? Two notes to self:

  1. Post the macro, when you ask for help.
  2. When you are having problems, remember to clear fields and start with a fresh query.

I'll settle on "problematic"... It's next to impossible to type a return/linefeed in there, but it can be pasted.

Always worth a "triple-click" -- if you've a rogue return then the whole field will highlight

Whereas you only want the text you've entered to be selected

If it's the first you can right-arrow through to the next line(s) and delete.

The other, properly nerdy, way to check is to right-click the action, "Copy as XML", and paste into a text editor. Lines that start tight to the left margin are part of multiline strings and really easy to spot -- in this case:

        <!-- snip earlier stuff -->
		<string>SearchReplace</string>
		<key>Replace</key>
		<string>:</string>
		<key>Search</key>
		<string>\R(?=\d)
\r</string>
		<key>Source</key>
		<string>Variable</string>
        <!-- snip later stuff -->

...and you can see that extra line in the "Search" string.

โŒ˜A works as well.

1 Like

Yes, and I also missed out โŒ˜A, โŒ˜C, paste into text editor. While I love KM's "many ways to do a thing", sometimes there's too many to remember!

1 Like

Since this is straightforward in Haskell, I post this as an alternative:

Rows rejoined with a colon delimiter.kmmacros (7.4 KB)

Macro-Notes
  • Macros are always disabled when imported into the Keyboard Maestro Editor.
    • The user must ensure the macro is enabled.
    • The user must also ensure the macro's parent macro-group is enabled.
System Information
  • macOS 13.1
  • Keyboard Maestro v10.2

Haskell source code:

import Data.List

main :: IO ()
main = interact $ intercalate ":" . lines
3 Likes

With Perl โ€“ just for fun...


Download: Replace Newline Characters (Perl) v1..00.kmmacros (5.5 KB)

Macro-Image

Keyboard Maestro Export

Macro-Notes
  • Macros are always disabled when imported into the Keyboard Maestro Editor.
    • The user must ensure the macro is enabled.
    • The user must also ensure the macro's parent macro-group is enabled.

System Information
  • macOS 10.14.6
  • Keyboard Maestro v10.2

1 Like

Interesting solution. Just curious, what's -0777 ?

P.D.: Seems like a (cryptic) reference to James Bond.

The Command-line Options

-0 specifies the input record separator:

โ€œ-0777 will force Perl to read the whole file in one shot because 0777 is not a legal character value.โ€

2 Likes

And there's always room for an AppleScript version... Useful because paragraphs of is line-ending agnostic -- if you want to prove that for yourself, set the text to a mix of old-Mac, Unix, and Windows line-endings such as

1%Return%2%LineFeed%3%Return%%LineFeed%4%Return%5%Return%

AS Paragraphs Demo.kmmacros (2.4 KB)

Images

I'm sure reverse of rest of reverse of aList isn't the most efficient way of dropping the last item of a list (in this case, to deal with a trailing line-ending) but I use it because it makes me smile every time :wink:

--------------------------------------------------------
# Auth: Christopher Stone <scriptmeister@thestoneforge.com>
# dCre: 2016/05/08 00:59
# dMod: 2023/03/25 20:10
# Appl: AppleScriptObjC
# Task: RegEx Find-Replace Handler.
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @ASObjC, @Find, @Replace, @Text, @RegEx, @cngStr, @Change
--------------------------------------------------------
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions
--------------------------------------------------------

set dataString to "
125429
125426
125429
125426
"

set newStr to its cngStr:"\\A\\s+|\\s+\\Z" intoString:"" inString:dataString
set newStr to its cngStr:"\\R" intoString:":" inString:newStr

--------------------------------------------------------
--ยป HANDLERS
--------------------------------------------------------
on cngStr:findString intoString:replaceString inString:dataString
   set anNSString to current application's NSString's stringWithString:dataString
   set dataString to (anNSString's ยฌ
      stringByReplacingOccurrencesOfString:findString withString:replaceString ยฌ
         options:(current application's NSRegularExpressionSearch) range:{0, length of dataString}) as text
end cngStr:intoString:inString:
--------------------------------------------------------
2 Likes

My approach to this was similar to the original, except I just used a string search & replace rather than an expression.

Using a string \n the "for" field (line feed), then told it to replace with a colon.

Worked perfectly for me.
Replacing Newline Characters.kmmacros (2.8 KB)

Hey Rocky,

There's nothing wrong with this approach.

However โ€“ the character in question is not a return it's a linefeed. (macOS converted from carriage returns to linefeeds long ago.)

You're better off using the \n meta-character which will be properly interpreted by KM in the plain string find/replace action, because you can eyeball the replace string and not have to guess, test, or document it.

If you really needed a return character that would be: \r

-Chris

I tried the \r but it didn't work. Didn't try the linefeed \n, but testing it just now, it does work.
Thanks.

1 Like