Replace Strings with Evaluated String Based on Matched Group (Elegant Way, Not Using for .. In)

Replace strings with evaluated string based on matched group (elegant way, not using for .. in)

awk oneliner: (the datetime format could be different from your output)

awk '/^[0-9]{1,10} [0-9]{1,4}/{l=$1+$2; "date --date=@"$1|getline d1; "date --date=@"l|getline d2;print d1" - "d2;next;}1' file

test:

kent$  echo "1357222500 3600 ...
Maybe intermediate strings...
1357226100 3600 ...
Maybe intermediate strings...
..."|awk '/^[0-9]{1,10} [0-9]{1,4}/{l=$1+$2; "date --date=@"$1|getline d1; "date --date=@"l|getline d2;print d1" - "d2;next;}1'
Thu Jan 3 15:15:00 CET 2013 - Thu Jan 3 16:15:00 CET 2013
Maybe intermediate strings...
Thu Jan 3 15:15:00 CET 2013 - Thu Jan 3 17:15:00 CET 2013
Maybe intermediate strings...
...

Gnu sed

if you have gnu sed, the idea from your "not working" sed line could work in real world by applying gnu sed's s/foo/shell cmds/ge see below:

sed -r 's#^([0-9]{1,10}) ([0-9]{1,4})(.*$)#echo $(date --date=@\1 )" - "$(date --date=@$((\1+\2)))#ge'  file

test

kent$  echo "1357222500 3600 ...
Maybe intermediate strings...
1357226100 3600 ...
Maybe intermediate strings...
..."|sed -r 's#^([0-9]{1,10}) ([0-9]{1,4})(.*$)#echo $(date --date=@\1 )" - "$(date --date=@$((\1+\2)))#ge'
Thu Jan 3 15:15:00 CET 2013 - Thu Jan 3 16:15:00 CET 2013
Maybe intermediate strings...
Thu Jan 3 16:15:00 CET 2013 - Thu Jan 3 17:15:00 CET 2013
Maybe intermediate strings...
...

if I would work on this, personally I would go with awk. because it is straightforward and easy to write.

at the end I paste my sed/awk version info :

kent$  sed --version|head -1
sed (GNU sed) 4.2.2

kent$ awk -V|head -1
GNU Awk 4.0.1

Java string replace regex pattern with evaluated key

You should make use of the Matcher#appendReplacement and Matcher#appendTail APIs here:

Map<String, String> keyValueMap = new HashMap<>();
keyValueMap.put("places", "to America");
keyValueMap.put("things", "events");
String input = "I want to go to {places} where {things} are happening.";
Pattern pattern = Pattern.compile("\\{(.*?)\\}");
Matcher matcher = pattern.matcher(input);
StringBuffer buffer = new StringBuffer();

while(matcher.find()) {
matcher.appendReplacement(buffer, keyValueMap.get(matcher.group(1)));
}
matcher.appendTail(buffer);
System.out.println(buffer.toString());

This prints:

I want to go to to America where events are happening.

Replace named group in regex with value

No, it's not possible to use a regular expression without providing input. It has to have something to work with, the pattern can not add any data to the result, everything has to come from the input or the replacement.

Intead of using String.Format, you can use a look behind and a look ahead to specify the part between "abc_" and "_def", and replace it:

string result = Regex.Replace(input, @"(?<=abc_)\d+(?=_def)", "999");

Replace multiple strings with multiple other strings

As an answer to:

looking for an up-to-date answer

If you are using "words" as in your current example, you might extend the answer of Ben McCormick using a non capture group and add word boundaries \b at the left and at the right to prevent partial matches.

\b(?:cathy|cat|catch)\b
  • \b A word boundary to prevent a partial match
  • (?: Non capture group
    • cathy|cat|catch match one of the alternatives
  • ) Close non capture group
  • \b A word boundary to prevent a partial match

Example for the original question:

let str = "I have a cat, a dog, and a goat.";
const mapObj = {
cat: "dog",
dog: "goat",
goat: "cat"
};
str = str.replace(/\b(?:cat|dog|goat)\b/gi, matched => mapObj[matched]);
console.log(str);

Not able to build an array & print it out in AWK

index is built-in GNU AWK function, thus you have syntax error when you try to use it as array key. Change index to inx to avoid syntax error and apply some changes to last action to get desired output

Let file.txt content be

1|Sam|Smith|Seatle
2|Barry|Jones|Seatle
3|Garry|Brown|Houston
4|George|Bla|LA
5|Celine|Wood|Atlanta
6|Jody|Ford|Chicago

then

awk 'BEGIN { FS="|" } { employee[$1]=$0; next } END{ for (inx=1; inx<=NR; inx++){print inx ":" employee[inx]} }' file.txt

output

1:1|Sam|Smith|Seatle
2:2|Barry|Jones|Seatle
3:3|Garry|Brown|Houston
4:4|George|Bla|LA
5:5|Celine|Wood|Atlanta
6:6|Jody|Ford|Chicago
7:

Explanation: changed index to inx, change for's check to less equal number of rows (NR), register last action as END (execute after processing all files). Note that for for Arrays might be better fit for that rather than for you have used depending on your requirements.

(tested in gawk 4.2.1)

Regex C# replace matched fields with multiple results

I would use some lambda functions:

// This one gets the index from the list of matches
private static string LookupReplace(string text, List<string> newList)
{
var result = "~" + newList.IndexOf(text).ToString() + "~";
return result;
}

// This one just increments a global counter
private static string NumberedReplace()
{
i++;
return "~" + i.ToString() + "~";
}

public static int i = -1;

public static void Main()
{
string text = "iif(instr(|Wellington, New Zealand|,|,|)>0,|Wellington, New Zealand|,|Wellington, New Zealand| & |, | & |New Zealand|) & | to | & iif(instr(|Jeddah, Saudi Arabia|,|,|)>0,|Jeddah, Saudi Arabia|,|Jeddah, Saudi Arabia| & |, | & |Saudi Arabia|) & iif(|Jeddah, Saudi Arabia|=||,||,| via | & |Jeddah, Saudi Arabia|)";
var re = new Regex(@"\|.*?\|");
var newList = re.Matches(text)
.OfType<Match>()
.Select(m => m.Value)
.ToList();
// First replace with index
string result = re.Replace(text, x => LookupReplace(x.Value, newList));
Console.WriteLine(result);

// Second replace with counter
result = re.Replace(text, x => NumberedReplace());
Console.WriteLine(result);
}

ideone demo

Output of each replace:

iif(instr(~0~,~1~)>0,~0~,~0~ & ~4~ & ~5~) & ~6~ & iif(instr(~7~,~1~)>0,~7~,~7~ & ~4~ & ~12~) & iif(~7~=~14~,~14~,~16~ & ~7~)
iif(instr(~0~,~1~)>0,~2~,~3~ & ~4~ & ~5~) & ~6~ & iif(instr(~7~,~8~)>0,~9~,~10~ & ~11~ & ~12~) & iif(~13~=~14~,~15~,~16~ & ~17~)

R - How to replace a string from multiple matches (in a data frame)

Edit

Based on the input from Sri's comment I would suggest using:

library(gsubfn)
# words to be replaced
a <-c("Whats your","Whats your name", "name", "fro")
# their replacements
b <- c("What is yours","what is your name","names","froth")
# named list as an input for gsubfn
replacements <- setNames(as.list(b), a)
# the test string
input_string = "fro Whats your name and Where're name you from to and fro I Whats your"
# match entire words
gsubfn(paste(paste0("\\w*", names(replacements), "\\w*"), collapse = "|"), replacements, input_string)

Original

I would not say this is easier to read than your simple loop, but it might take better care of the overlapping replacements:

# define the sample dataset
input_string = "Whats your name and Where're you from"
matching <- data.frame(from_word=c("Whats your name", "name", "fro", "Where're", "Whats"),
to_word=c("what is your name","names","froth", "where are", "Whatsup"))

# load used library
library(gsubfn)

# make sure data is of class character
matching$from_word <- as.character(matching$from_word)
matching$to_word <- as.character(matching$to_word)

# extract the words in the sentence
test <- unlist(str_split(input_string, " "))
# find where individual words from sentence match with the list of replaceble words
test2 <- sapply(paste0("\\b", test, "\\b"), grepl, matching$from_word)
# change rownames to see what is the format of output from the above sapply
rownames(test2) <- matching$from_word
# reorder the data so that largest replacement blocks are at the top
test3 <- test2[order(rowSums(test2), decreasing = TRUE),]
# where the word is already being replaced by larger chunk, do not replace again
test3[apply(test3, 2, cumsum) > 1] <- FALSE

# define the actual pairs of replacement
replacements <- setNames(as.list(as.character(matching[,2])[order(rowSums(test2), decreasing = TRUE)][rowSums(test3) >= 1]),
as.character(matching[,1])[order(rowSums(test2), decreasing = TRUE)][rowSums(test3) >= 1])

# perform the replacement
gsubfn(paste(as.character(matching[,1])[order(rowSums(test2), decreasing = TRUE)][rowSums(test3) >= 1], collapse = "|"),
replacements,input_string)

Replace matches with regex

Something like this might do:

const evaluate = function(str) {
if (str && str.startsWith("t")) {return str.toUpperCase();}
throw "Gotta hava a 'T'";
};

"ab$test$cd $something$ that is $tricky$.".replace(/\$([^$]*)\$/g;, function(str, match) {
try {
return evaluate(match);
} catch(e) {
return str;
}
}); //=> "abTESTcd $something$ that is TRICKY."

But I agree with the comment that you might be better returning a different signal (undefined? null?) from evaluate rather than throwing for this case. And then the function body could simply be something like:

        return evaluate(match) || str;

The point is the capturing group in the regex: /\$([^$]*)\$/g;, which becomes a parameter to the replacement function.



Related Topics



Leave a reply



Submit