3

HI I want to replace a forward slash by a space, but only if it appears once.

 str_replace_all( 'NOOOOO//ABCDEFGHI/asdfasd//sdkksksks', "/(?!=/)", " ")

Here I want the output to be: NOOOOO//ABCDEFGHI asdfasd//sdkksksks

Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
user1420372
  • 2,077
  • 3
  • 25
  • 42

3 Answers3

2

Try the following option with sub:

input <- "NOOOOO//ABCDEFGHI/asdfasd//sdkksksks"
gsub("(?<!/)/(?!/)", " ", input, perl=TRUE)

[1] "NOOOOO//ABCDEFGHI asdfasd//sdkksksks"

The strategy here is to use the pattern (?<!/)/(?!/), which matches a single forward slash which it surrounded on both sides by anything other than another forward slash.

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • So "not a slash" can be represented in two ways in regex `!/` and `[^/]` ? Is the former perl specific ? – Ronak Shah Sep 11 '19 at 01:05
  • 1
    @RonakShah I'd say that `!/` is part of the negative look-behind, i.e. `(?<!text)` is the negation of a positive look-behind `(?<=text)`. – Maurits Evers Sep 11 '19 at 01:38
  • 1
    @RonakShah Only `[^/]` by itself means "not a slash." `!/` only has meaning when part of a lookaround, e.g. `(?!/)` means "what follows is not a slash." – Tim Biegeleisen Sep 11 '19 at 01:38
  • 1
    @RonakShah they are quite different lookarounds are zero length match they do not consume the word, where as character class do consume the word, `[^/]` means match anything which is not `/`, and on the other hand `some pattern(?!)` means `some pattern` should not be followed by `/` – Code Maniac Sep 11 '19 at 01:51
2

Instead of using lookarounds, you could make use of (*SKIP)(*FAIL) using sub with the option perl=TRUE to match the characters that should not be part of the match.

In this case you could match 2 or more forward slashes that should not be part of the match. After that, match a single forward slash to be replaced with a space.

/{2,}(*SKIP)(*F)|/

Regex demo | R demo

For example

s <- "NOOOOO//ABCDEFGHI/asdfasd//sdkksksks"
gsub("/{2,}(*SKIP)(*F)|/", " ", s, perl=TRUE)

Output

[1] "NOOOOO//ABCDEFGHI asdfasd//sdkksksks"
The fourth bird
  • 154,723
  • 16
  • 55
  • 70
  • Wow! Thanks - I wasn't even aware of SKIP/FAIL. I had been thinking of the look-around method but will certainly start using this construct. – user1420372 Sep 11 '19 at 23:02
1

Another way is to use capture group

 (^|[^\/\n])\/([^\/\n]|$)

Than replace with \1 \2

enter image description here

Regex Demo

Code Maniac
  • 37,143
  • 5
  • 39
  • 60
  • 1
    Thanks, I got this to work using: str_replace_all(input, "(^|[^/])/([^/]|$)", "\\1 \\2"). Great pickup on the newline characters, although not relevant for me in this case, I can see that it generally would be. – user1420372 Sep 11 '19 at 07:05