I wish you can help me I want to do is I have two variables of type string
String text = "HELLO HOW ARE YOU";
String value = "abc";
I want to do is see if any character of the variable values in text and contains tested but I only detects a single character but not
if(text.toUpperCase().contains(value.toUpperCase()))throw new Exception("NOT LETTERS");
You could use the List API...
String text = "HELLO HOW ARE YOU";
String value = "abc";
List<String> left = new ArrayList<>(Arrays.asList(text.toUpperCase().split("")));
List<String> right = new ArrayList<>(Arrays.asList(value.toUpperCase().split("")));
boolean hasAny = left.removeAll(right);
Basically this creates a List of each word then removes all the matches from the second in the first. A return value of true means the first List was modified, meaning it had matching values. You might even be able to compare the difference in size to determine how many matches there were.
You could also use Java 8's Stream API...
String text = "HELLO HOW ARE YOU";
String value = "abc";
List<String> left = new ArrayList<>(Arrays.asList(text.toUpperCase().split("")));
List<String> right = new ArrayList<>(Arrays.asList(value.toUpperCase().split("")));
boolean anyMatch = left.stream().anyMatch((String t) -> {
return right.contains(t);
});
Again, this will simply return true if the first List contains ANY of the values in the second List
Now, if you wanted to know which values actually matched, you might be able to use something like...
Set<String> collect = right.stream().filter((String t) -> {
return left.contains(t);
}).collect(Collectors.toSet());
System.out.println(collect);
Which in you example, would print
[A]
You can try like this:
public static boolean findLetters() {
String text = "HELLO HOW ARE YOU";
String value = "abc";
for (int i = 0; i < value.length(); i++) {
if (text.indexOf(value.toUpperCase().charAt(i)) == -1) {
return false;
}
}
return true;
}
Not sure if I understand the question quite well, but you may try this:
String text = "HELLO HOW ARE YOU";
String value = "abc";
for(char c : value.toUpperCase().toCharArray()) {
if (text.indexOf(c) != -1) {
throw new Exception("NOT LETTERS");
}
}
Related
I have solved Two Strings problem in HackerRank
Here is the problem.
Given two strings, determine if they share a common substring. A
substring may be as small as one character.
For example, the words "a", "and", "art" share the common substring.
The words "be" and "cat" do not share a substring.
Function Description
Complete the function twoStrings in the editor below. It should return
a string, either YES or NO based on whether the strings share a common
substring.
twoStrings has the following parameter(s):
s1, s2: two strings to analyze .
Output Format
For each pair of strings, return YES or NO.
However, when extra-long strings are subjected, my code does not run within the time limit. Any suggestions to improve efficiency? I think I can improve substring finding with using the Stream API. But I'm not sure how to use it in this context. Could someone please help me to understand this better?
public static void main(String[] args) {
String s1 = "hi";
String s2 = "world";
checkSubStrings(s1, s2);
}
static void checkSubStrings(String s1, String s2) {
Map<String, Long> s1Map = new HashMap<>();
Map<String, Long> s2Map = new HashMap<>();
findAllSubStrings(s1, s1Map);
findAllSubStrings(s2, s2Map);
boolean isContain = s2Map.entrySet().stream().anyMatch(i -> s1Map.containsKey(i.getKey()) );
if (isContain) {
System.out.println("YES");
} else {
System.out.println("NO");
}
}
static void findAllSubStrings(String s, Map<String, Long> map) {
for (int i = 0; i < s.length(); i++) {
String subString = s.substring(i);
for (int j = subString.length(); j > 0; j--) {
String subSubString = subString.substring(0, j);
if (map.containsKey(subSubString)) {
map.put(subSubString, map.get(subSubString) + 1);
} else {
if (!subSubString.equals(""))
map.put(subSubString, 1L);
}
}
}
}
Update
I just solved the question using HashSets.
I optimized the code using Set. Now it runs with very large Strings.
static String twoStrings(String s1, String s2) {
String result = null;
Set<Character> s1Set = new HashSet<>();
Set<Character> s2Set = new HashSet<>();
for(char a : s1.toCharArray()){
s1Set.add(a);
}
for(char a : s2.toCharArray()){
s2Set.add(a);
}
boolean isContain = s2Set.stream().anyMatch(s1Set::contains);
if(isContain){
result = "YES";
} else {
result = "NO";
}
return result;
}
If 2 strings share an N (>=2) character substring, they also share an N-1 character substring (because you can chop a character off the end of the common substring, and this will still be found in both strings). Extending this argument, they also share a 1-character substring.
As such, all you need to check are single-character substrings.
Fill your maps with single-character substrings instead, and you will avoid creating (and checking) unnecessary substrings. (And just use a Set instead of a Map, you never use the counts).
// Yields a `Set<Integer>`, which can be used directly to check.
return s.codePoints().boxed().collect(Collectors.toSet());
as it mentioned in the title, I have this code
String a = flett("AM ","L","GEDS","ORATKRR","","R TRTE","IO","TGAUU");
public static String flett(String... s){
StringBuilder merge = new StringBuilder();
for (int i = 0; i < s.length; i++) {
merge.append(s.charAt(i));
}
return merge;
}
I got an error at chartAt(i) ?
how for example I can call every character in the array s and save them into merge or call an specific character like the first character from each one and save them into merge ?
s[i].charAt(j);
where i - the index of an array, j - the index of a letter within a String.
A Java 8 method that collects the first letter of each array's element might look like
public String flett(String... s) {
return Arrays.stream(s)
.map(i -> i.length() > 0 ? String.valueOf(i.charAt(0)) : "")
.collect(Collectors.joining());
}
For the array "AM ","L","GEDS","ORATKRR","","R TRTE","IO","TGAUU", it results in "ALGORIT".
You have to use a variable amount of String parameters, then concatenate all first characters of non empty Strings of the parameters and return the concatenated object:
public static void main(String[] args) {
String s = flett("AM ","L","GEDS","ORATKRR","","R TRTE","IO","TGAUU", "HOLA", "MMMMH");
System.out.println(s);
}
// Please note the parameter, it takes a various amount of Strings
public static String flett(String ... values) {
// create something that concatenates Strings (other options possible)
StringBuilder sb = new StringBuilder();
// the parameters are now an array of Strings, which you can "foreach"
for (String s : values) {
// check for empty ones and skip those
if (!s.equals("")) {
// append the first character of a valid parameter
sb.append(s.charAt(0));
}
}
return sb.toString();
}
Be surprised by the output…
This method get some Strings and Create String from the first character of each String.
public static String flett(String... s) {
StringBuilder res = new StringBuilder(s.length);
for (String a : s) {
if (!a.isEmpty()) {
res.append(a.charAt(0));
}
}
return res.toString();
}
I have docx document with some placeholders. Now I should replace them with other content and save new docx document. I started with docx4j and found this method:
public static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) {
List<Object> result = new ArrayList<Object>();
if (obj instanceof JAXBElement) obj = ((JAXBElement<?>) obj).getValue();
if (obj.getClass().equals(toSearch))
result.add(obj);
else if (obj instanceof ContentAccessor) {
List<?> children = ((ContentAccessor) obj).getContent();
for (Object child : children) {
result.addAll(getAllElementFromObject(child, toSearch));
}
}
return result;
}
public static void findAndReplace(WordprocessingMLPackage doc, String toFind, String replacer){
List<Object> paragraphs = getAllElementFromObject(doc.getMainDocumentPart(), P.class);
for(Object par : paragraphs){
P p = (P) par;
List<Object> texts = getAllElementFromObject(p, Text.class);
for(Object text : texts){
Text t = (Text)text;
if(t.getValue().contains(toFind)){
t.setValue(t.getValue().replace(toFind, replacer));
}
}
}
}
But that only work rarely because usually the placeholders splits across multiple texts runs.
I tried UnmarshallFromTemplate but it work rarely too.
How this problem could be solved?
You can use VariableReplace to achieve this which may not have existed at the time of the other answers.
This does not do a find/replace per se but works on placeholders eg ${myField}
java.util.HashMap mappings = new java.util.HashMap();
VariablePrepare.prepare(wordMLPackage);//see notes
mappings.put("myField", "foo");
wordMLPackage.getMainDocumentPart().variableReplace(mappings);
Note that you do not pass ${myField} as the field name; rather pass the unescaped field name myField - This is rather inflexible in that as it currently stands your placeholders must be of the format ${xyz} whereas if you could pass in anything then you could use it for any find/replace. The ability to use this also exists for C# people in docx4j.NET
See here for more info on VariableReplace or here for VariablePrepare
Good day, I made an example how to quickly replace text to something you need
by regexp. I find ${param.sumname} and replace it in document.
Note, you have to insert text as 'text only'!
Have fun!
WordprocessingMLPackage mlp = WordprocessingMLPackage.load(new File("filepath"));
replaceText(mlp.getMainDocumentPart());
static void replaceText(ContentAccessor c)
throws Exception
{
for (Object p: c.getContent())
{
if (p instanceof ContentAccessor)
replaceText((ContentAccessor) p);
else if (p instanceof JAXBElement)
{
Object v = ((JAXBElement) p).getValue();
if (v instanceof ContentAccessor)
replaceText((ContentAccessor) v);
else if (v instanceof org.docx4j.wml.Text)
{
org.docx4j.wml.Text t = (org.docx4j.wml.Text) v;
String text = t.getValue();
if (text != null)
{
t.setSpace("preserve"); // needed?
t.setValue(replaceParams(text));
}
}
}
}
}
static Pattern paramPatern = Pattern.compile("(?i)(\\$\\{([\\w\\.]+)\\})");
static String replaceParams(String text)
{
Matcher m = paramPatern.matcher(text);
if (!m.find())
return text;
StringBuffer sb = new StringBuffer();
String param, replacement;
do
{
param = m.group(2);
if (param != null)
{
replacement = getParamValue(param);
m.appendReplacement(sb, replacement);
}
else
m.appendReplacement(sb, "");
}
while (m.find());
m.appendTail(sb);
return sb.toString();
}
static String getParamValue(String name)
{
// replace from map or something else
return name;
}
I created a library to publish my solution because it's quite a lot of code: https://github.com/phip1611/docx4j-search-and-replace-util
The workflow is the following:
First step:
// (this method was part of your question)
List<Text> texts = getAllElementFromObject(docxDocument.getMainDocumentPart(), Text.class);
This way we get all actual Text-content in the correct order but without style markup in-between. We can edit the Text-objects (by setValue) and keep styles.
Resulting problem: Search-text/placeholders can be split accoss multiple Text-instances (because there can be style markup that is invisble in-between in original document), e.g. ${FOOBAR}, ${ + FOOBAR}, or $ + {FOOB + AR}
Second step:
Concat all Text-objects to a full string / "complete string"
Optional<String> completeStringOpt = texts.stream().map(Text::getValue).reduce(String::concat);
Third step:
Create a class TextMetaItem. Each TextMetaItem knows for it's Text-object where it's content begins and ends in the complete string. E.g. If the Text-objects for "foo" and "bar" results in the complete string "foobar" than indices 0-2 belongs to "foo"-Text-object and 3-5 to "bar"-Text-object. Build a List<TextMetaItem>
static List<TextMetaItem> buildMetaItemList(List<Text> texts) {
final int[] index = {0};
final int[] iteration = {0};
List<TextMetaItem> list = new ArrayList<>();
texts.forEach(text -> {
int length = text.getValue().length();
list.add(new TextMetaItem(index[0], index[0] + length - 1, text, iteration[0]));
index[0] += length;
iteration[0]++;
});
return list;
}
Fourth step:
Build a Map<Integer, TextMetaItem> where the key is the index/char in the complete string. This means the map's length equals completeString.length()
static Map<Integer, TextMetaItem> buildStringIndicesToTextMetaItemMap(List<Text> texts) {
List<TextMetaItem> metaItemList = buildMetaItemList(texts);
Map<Integer, TextMetaItem> map = new TreeMap<>();
int currentStringIndicesToTextIndex = 0;
// + 1 important here!
int max = metaItemList.get(metaItemList.size() - 1).getEnd() + 1;
for (int i = 0; i < max; i++) {
TextMetaItem currentTextMetaItem = metaItemList.get(currentStringIndicesToTextIndex);
map.put(i, currentTextMetaItem);
if (i >= currentTextMetaItem.getEnd()) {
currentStringIndicesToTextIndex++;
}
}
return map;
}
interim result:
Now you have enough metadata to delegate every action you want to do on the complete string to the corresponding Text object! (To change the content of Text-objects you just need to call (#setValue()) That's all what's needed in Docx4J to edit text. All style info etc will be preserved!
last step: search and replace
build a method that finds all occurrences of your possible placeholders. You should create a class like FoundResult(int start, int end) that stores begin and end indices of a found value (placeholder) in the complete string
public static List<FoundResult> findAllOccurrencesInString(String data, String search) {
List<FoundResult> list = new ArrayList<>();
String remaining = data;
int totalIndex = 0;
while (true) {
int index = remaining.indexOf(search);
if (index == -1) {
break;
}
int throwAwayCharCount = index + search.length();
remaining = remaining.substring(throwAwayCharCount);
list.add(new FoundResult(totalIndex + index, search));
totalIndex += throwAwayCharCount;
}
return list;
}
using this I build a new list of ReplaceCommands. A ReplaceCommand is a simple class and stores a FoundResult and the new value.
next you must order this list from the last item to the first (order by position in complete string)
now you can write a replace all algorithm because you know what action needs to be done on which Text-object. We did (2) so that replace operations won't invalidate indices of other FoundResults.
3.1.) find Text-object(s) that needs to be changed
3.2.) call getValue() on them
3.3.) edit the string to the new value
3.4.) call setValue() on the Text-objects
This is the code that does all the magic. It executes a single ReplaceCommand.
/**
* #param texts All Text-objects
* #param replaceCommand Command
* #param map Lookup-Map from index in complete string to TextMetaItem
*/
public static void executeReplaceCommand(List<Text> texts, ReplaceCommand replaceCommand, Map<Integer, TextMetaItem> map) {
TextMetaItem tmi1 = map.get(replaceCommand.getFoundResult().getStart());
TextMetaItem tmi2 = map.get(replaceCommand.getFoundResult().getEnd());
if (tmi2.getPosition() - tmi1.getPosition() > 0) {
// it can happen that text objects are in-between
// we can remove them (set to null)
int upperBorder = tmi2.getPosition();
int lowerBorder = tmi1.getPosition() + 1;
for (int i = lowerBorder; i < upperBorder; i++) {
texts.get(i).setValue(null);
}
}
if (tmi1.getPosition() == tmi2.getPosition()) {
// do replacement inside a single Text-object
String t1 = tmi1.getText().getValue();
int beginIndex = tmi1.getPositionInsideTextObject(replaceCommand.getFoundResult().getStart());
int endIndex = tmi2.getPositionInsideTextObject(replaceCommand.getFoundResult().getEnd());
String keepBefore = t1.substring(0, beginIndex);
String keepAfter = t1.substring(endIndex + 1);
tmi1.getText().setValue(keepBefore + replaceCommand.getNewValue() + keepAfter);
} else {
// do replacement across two Text-objects
// check where to start and replace
// the Text-objects value inside both Text-objects
String t1 = tmi1.getText().getValue();
String t2 = tmi2.getText().getValue();
int beginIndex = tmi1.getPositionInsideTextObject(replaceCommand.getFoundResult().getStart());
int endIndex = tmi2.getPositionInsideTextObject(replaceCommand.getFoundResult().getEnd());
t1 = t1.substring(0, beginIndex);
t1 = t1.concat(replaceCommand.getNewValue());
t2 = t2.substring(endIndex + 1);
tmi1.getText().setValue(t1);
tmi2.getText().setValue(t2);
}
}
This can be a problem. I cover how to mitigate broken-up text runs in this answer here: https://stackoverflow.com/a/17066582/125750
... but you might want to consider content controls instead. The docx4j source site has various content control samples here:
https://github.com/plutext/docx4j/tree/master/src/samples/docx4j/org/docx4j/samples
I have two different string String A="example"; String B="example";
if concat both the string i am getting examplexample. Is there any possibility to avoid repetition of string with same name..??
How about this ?
if(!a.equals(b)){// or if needed use contains() , equalIgnoreCase() depending on your need
//concat
}
The Strings are not different, the same String object is assigned to two different variables ("two pointers to the same memory address").
Consider dumping all strings to a Set before concatenating, this avoids duplicates in the concatenated sequence:
Set<String> strings = new HashSet<String>();
StringBuilder resultBuilder = new StringBuilder();
for (String s:getAllStrings()) { // some magic to get all your strings
if (strings.contains(s))
continue; // has been added already
resultBuilder.append(s); // concatenate
strings.add(s); // put string to set
}
String result = resultBuilder.toString();
You can. Try something like this
private String concatStringExample1(String firstString, String secondString) {
if(firstString.equalsIgnoreCase(secondString)) { // String matched
return firstString; // or return secondString
} else { // Not matched
return firstString.concat(secondString);
}
}
or
private String concatStringExample2(String firstString, String secondString) {
if(firstString != null && firstString != null ) {
if(firstString.toLowerCase().indexOf(secondString.toLowerCase()) >= 0)
return firstString;
else if(secondString.toLowerCase().indexOf(firstString.toLowerCase()) >= 0)
return secondString;
else
return firstString.concat(secondString);
} else {
return "";
}
}
Just create a Set (It has mathematics set behaviour, it won't accept the duplicate objects)
Set<String> strings = new HashSet<String>();
//Fill this set with all the String objects
strings.add(A)
Strings.add(B)
//Now iterate this set and create a String Object
StringBuilder resultBuilder = new StringBuilder();
for(String string:Strings){
resultBuilder.append(string);
}
return resultBuilder.toString()
`
Consider the following String :
5|12345|value1|value2|value3|value4+5|777|value1|value2|value3|value4?5|777|value1|value2|value3|value4+
Here is how I want to split string, split it with + so I get this result :
myArray[0] = "5|12345|value1|value2|value3|value4";
myArray[1] = "5|777|value1|value2|value3|value4?5|777|value1|value2|value3|value4";
if string has doesn't contain char "?" split it with "|" and continue to part II, if string does contain "?" split it and for each part split it with "|" and continue to part II.
Here is part II :
myObject.setAttribute1(newString[0]);
...
myObject.setAttribute4(newString[3]);
Here what I've got so far :
private static String input = "5|12345|value1|value2|value3|value4+5|777|value1|value2|value3|value4?5|777|value1|value2|value3|value4+";
public void mapObject(String input){
String[] myArray = null;
if (input.contains("+")) {
myArray = input.split("+");
} else {
myArray = new String[1];
myArray[0] = input;
}
for (int i = 0; i < myArray.length; i++) {
String[] secondaryArray = null;
String[] myObjectAttribute = null;
if (myArray[i].contains("?")) {
secondaryArray = temporaryString.myArray[i].split("?");
for (String string : secondaryArray) {
myObjectAttribute = string.split("\\|");
}
} else {
myObjectAttribute = myArray[i].toString().split("\\|");
}
myObject.setAttribute1(myObjectAttribute[0]);
...
myObject.setAttribute4(myObjectAttribute[3]);
System.out.println(myObject.toString());
}
Problem :
When I split myArray, going trough for with myArray[0], everything set up nice as it should.
Then comes the myArray[1], its split into two parts then the second part overrides the value of the first(how do I know that?). I've overridden toString() method of myObject, when I finish I print the set values so I know that it overrides it, does anybody know how can I fix this?
I'm not quite sure what the intention is here, but in this snippet of code
secondaryArray = temporaryString.split("?");
for (String string : secondaryArray) {
myObjectAttribute = string.split("\\|");
}
if secondaryArray has two elements after the split operation, you are iterating over each half and re-assigning myObjectAttribute to the output of string.split("\|") each time. It doesn't matter what is in the first element of secondaryArray, as after this code runs myObjectAttribute is going to contain the result of split("\\|") on the last element in the array.
Also, there is no point in calling .toString() on a String object as you do in temporaryString = myArray[i].toString().
The code doesn't seem to be able to handle the possible expansion of strings in the secondary case. To make the code clearer, I would use a List rather than array.
private static String input = "5|12345|value1|value2|value3|value4+5|777|value1|value2|value3|value4?5|777|value1|value2|value3|value4+";
private void split(List<String> input, List<String> output, String split) {
for (String s: input) {
if (s.contains(split))
{
output.addAll(Arrays.asList(s.split(Pattern.quote(split)));
}
else
output.add(s);
}
}
public void mapObject(String input) {
List<String> inputSrings = new ArrayList<String>();
List<String> splitPlus = new ArrayList<String>();
inputStrings.add(input);
split(inputStrings, splitPlus);
List<String> splitQuest = new ArrayList<String>();
split(splitPlus, splitQuest, "?");
for (String s: splitQuest) {
// you can now set the attributes from the values in the list
// splitPipe
String[] attributes = s.split("\\|");
myObject.setAttribute1(attributes[0]);
....
myObject.setAttribute4(attributes[3]);
System.out.println(myObject);
}
}