mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
Merge remote-tracking branch 'origin/v5-dev' into v5-dev
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.7.17-SNAPSHOT</version>
|
||||
<version>5.7.18-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-core</artifactId>
|
||||
|
@@ -5,7 +5,14 @@ import cn.hutool.core.lang.Opt;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.stream.StreamUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -48,8 +55,7 @@ public class CollStreamUtil {
|
||||
if (CollUtil.isEmpty(collection)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return StreamUtil.of(collection, isParallel)
|
||||
.collect(HashMap::new, (HashMap<K, V> m, V v) -> m.put(Opt.ofNullable(v).map(key).get(), v), HashMap::putAll);
|
||||
return toMap(collection, (v)-> Opt.ofNullable(v).map(key).get(), Function.identity(), isParallel);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,7 +88,8 @@ public class CollStreamUtil {
|
||||
if (CollUtil.isEmpty(collection)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return StreamUtil.of(collection, isParallel).collect(HashMap::new, (HashMap<K, V> m, E v) -> m.put(key.apply(v), value.apply(v)), HashMap::putAll);
|
||||
return StreamUtil.of(collection, isParallel)
|
||||
.collect(HashMap::new, (m, v) -> m.put(key.apply(v), value.apply(v)), HashMap::putAll);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -16,7 +16,6 @@ import java.util.Stack;
|
||||
*/
|
||||
public class Calculator {
|
||||
private final Stack<String> postfixStack = new Stack<>();// 后缀式栈
|
||||
private final Stack<Character> opStack = new Stack<>();// 运算符栈
|
||||
private final int[] operatPriority = new int[]{0, 3, 2, 1, -1, 1, 0, 2};// 运用运算符ASCII码-40做索引的运算符优先级
|
||||
|
||||
/**
|
||||
@@ -26,39 +25,7 @@ public class Calculator {
|
||||
* @return 计算结果
|
||||
*/
|
||||
public static double conversion(String expression) {
|
||||
final Calculator cal = new Calculator();
|
||||
expression = transform(expression);
|
||||
return cal.calculate(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将表达式中负数的符号更改
|
||||
*
|
||||
* @param expression 例如-2+-1*(-3E-2)-(-1) 被转为 ~2+~1*(~3E~2)-(~1)
|
||||
* @return 转换后的字符串
|
||||
*/
|
||||
private static String transform(String expression) {
|
||||
expression = StrUtil.cleanBlank(expression);
|
||||
expression = StrUtil.removeSuffix(expression, "=");
|
||||
final char[] arr = expression.toCharArray();
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
if (arr[i] == '-') {
|
||||
if (i == 0) {
|
||||
arr[i] = '~';
|
||||
} else {
|
||||
char c = arr[i - 1];
|
||||
if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == 'E' || c == 'e') {
|
||||
arr[i] = '~';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (arr[0] == '~' || (arr.length > 1 && arr[1] == '(')) {
|
||||
arr[0] = '-';
|
||||
return "0" + new String(arr);
|
||||
} else {
|
||||
return new String(arr);
|
||||
}
|
||||
return (new Calculator()).calculate(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,15 +35,16 @@ public class Calculator {
|
||||
* @return 计算结果
|
||||
*/
|
||||
public double calculate(String expression) {
|
||||
prepare(transform(expression));
|
||||
|
||||
Stack<String> resultStack = new Stack<>();
|
||||
prepare(expression);
|
||||
Collections.reverse(postfixStack);// 将后缀式栈反转
|
||||
String firstValue, secondValue, currentValue;// 参与计算的第一个值,第二个值和算术运算符
|
||||
String firstValue, secondValue, currentOp;// 参与计算的第一个值,第二个值和算术运算符
|
||||
while (false == postfixStack.isEmpty()) {
|
||||
currentValue = postfixStack.pop();
|
||||
if (false == isOperator(currentValue.charAt(0))) {// 如果不是运算符则存入操作数栈中
|
||||
currentValue = currentValue.replace("~", "-");
|
||||
resultStack.push(currentValue);
|
||||
currentOp = postfixStack.pop();
|
||||
if (false == isOperator(currentOp.charAt(0))) {// 如果不是运算符则存入操作数栈中
|
||||
currentOp = currentOp.replace("~", "-");
|
||||
resultStack.push(currentOp);
|
||||
} else {// 如果是运算符则从操作数栈中取两个值和该数值一起参与运算
|
||||
secondValue = resultStack.pop();
|
||||
firstValue = resultStack.pop();
|
||||
@@ -85,7 +53,7 @@ public class Calculator {
|
||||
firstValue = firstValue.replace("~", "-");
|
||||
secondValue = secondValue.replace("~", "-");
|
||||
|
||||
BigDecimal tempResult = calculate(firstValue, secondValue, currentValue.charAt(0));
|
||||
BigDecimal tempResult = calculate(firstValue, secondValue, currentOp.charAt(0));
|
||||
resultStack.push(tempResult.toString());
|
||||
}
|
||||
}
|
||||
@@ -98,6 +66,7 @@ public class Calculator {
|
||||
* @param expression 表达式
|
||||
*/
|
||||
private void prepare(String expression) {
|
||||
final Stack<Character> opStack = new Stack<>();
|
||||
opStack.push(',');// 运算符放入栈底元素逗号,此符号优先级最低
|
||||
char[] arr = expression.toCharArray();
|
||||
int currentIndex = 0;// 当前字符的位置
|
||||
@@ -152,7 +121,7 @@ public class Calculator {
|
||||
*
|
||||
* @param cur 下标
|
||||
* @param peek peek
|
||||
* @return 优先级
|
||||
* @return 优先级,如果cur高或相等,返回true,否则false
|
||||
*/
|
||||
private boolean compare(char cur, char peek) {// 如果是peek优先级高于cur,返回true,默认都是peek优先级要低
|
||||
final int offset = 40;
|
||||
@@ -199,4 +168,34 @@ public class Calculator {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将表达式中负数的符号更改
|
||||
*
|
||||
* @param expression 例如-2+-1*(-3E-2)-(-1) 被转为 ~2+~1*(~3E~2)-(~1)
|
||||
* @return 转换后的字符串
|
||||
*/
|
||||
private static String transform(String expression) {
|
||||
expression = StrUtil.cleanBlank(expression);
|
||||
expression = StrUtil.removeSuffix(expression, "=");
|
||||
final char[] arr = expression.toCharArray();
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
if (arr[i] == '-') {
|
||||
if (i == 0) {
|
||||
arr[i] = '~';
|
||||
} else {
|
||||
char c = arr[i - 1];
|
||||
if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == 'E' || c == 'e') {
|
||||
arr[i] = '~';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (arr[0] == '~' || (arr.length > 1 && arr[1] == '(')) {
|
||||
arr[0] = '-';
|
||||
return "0" + new String(arr);
|
||||
} else {
|
||||
return new String(arr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -20,6 +20,8 @@ import java.util.Map;
|
||||
* <pre>
|
||||
* key1=v1&key2=&key3=v3
|
||||
* </pre>
|
||||
* 查询封装分为解析查询字符串和构建查询字符串,解析可通过charset为null来自定义是否decode编码后的内容,<br>
|
||||
* 构建则通过charset是否为null是否encode参数键值对
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.3.1
|
||||
|
@@ -514,20 +514,20 @@ public class XmlUtil {
|
||||
*
|
||||
* @param doc XML文档
|
||||
* @param path 文件路径绝对路径或相对ClassPath路径,不存在会自动创建
|
||||
* @param charset 自定义XML文件的编码,如果为{@code null} 读取XML文档中的编码,否则默认UTF-8
|
||||
* @param charsetName 自定义XML文件的编码,如果为{@code null} 读取XML文档中的编码,否则默认UTF-8
|
||||
*/
|
||||
public static void toFile(Document doc, String path, String charset) {
|
||||
if (StrUtil.isBlank(charset)) {
|
||||
charset = doc.getXmlEncoding();
|
||||
public static void toFile(Document doc, String path, String charsetName) {
|
||||
if (StrUtil.isBlank(charsetName)) {
|
||||
charsetName = doc.getXmlEncoding();
|
||||
}
|
||||
if (StrUtil.isBlank(charset)) {
|
||||
charset = CharsetUtil.UTF_8;
|
||||
if (StrUtil.isBlank(charsetName)) {
|
||||
charsetName = CharsetUtil.UTF_8;
|
||||
}
|
||||
|
||||
BufferedWriter writer = null;
|
||||
try {
|
||||
writer = FileUtil.getWriter(path, charset, false);
|
||||
write(doc, writer, charset, INDENT_DEFAULT);
|
||||
writer = FileUtil.getWriter(path, CharsetUtil.charset(charsetName), false);
|
||||
write(doc, writer, charsetName, INDENT_DEFAULT);
|
||||
} finally {
|
||||
IoUtil.close(writer);
|
||||
}
|
||||
@@ -783,10 +783,10 @@ public class XmlUtil {
|
||||
*/
|
||||
public static Element getElement(Element element, String tagName) {
|
||||
final NodeList nodeList = element.getElementsByTagName(tagName);
|
||||
if (nodeList == null || nodeList.getLength() < 1) {
|
||||
final int length = nodeList.getLength();
|
||||
if (length < 1) {
|
||||
return null;
|
||||
}
|
||||
int length = nodeList.getLength();
|
||||
for (int i = 0; i < length; i++) {
|
||||
Element childEle = (Element) nodeList.item(i);
|
||||
if (childEle == null || childEle.getParentNode() == element) {
|
||||
@@ -1499,22 +1499,20 @@ public class XmlUtil {
|
||||
*/
|
||||
private void examineNode(Node node, boolean attributesOnly) {
|
||||
final NamedNodeMap attributes = node.getAttributes();
|
||||
if (null != attributes) {
|
||||
for (int i = 0; i < attributes.getLength(); i++) {
|
||||
Node attribute = attributes.item(i);
|
||||
storeAttribute(attribute);
|
||||
}
|
||||
final int length = attributes.getLength();
|
||||
for (int i = 0; i < length; i++) {
|
||||
Node attribute = attributes.item(i);
|
||||
storeAttribute(attribute);
|
||||
}
|
||||
|
||||
if (false == attributesOnly) {
|
||||
final NodeList childNodes = node.getChildNodes();
|
||||
if (null != childNodes) {
|
||||
Node item;
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
item = childNodes.item(i);
|
||||
if (item.getNodeType() == Node.ELEMENT_NODE)
|
||||
examineNode(item, false);
|
||||
}
|
||||
Node item;
|
||||
final int childLength = childNodes.getLength();
|
||||
for (int i = 0; i < childLength; i++) {
|
||||
item = childNodes.item(i);
|
||||
if (item.getNodeType() == Node.ELEMENT_NODE)
|
||||
examineNode(item, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -130,4 +130,11 @@ public class UrlQueryTest {
|
||||
final String a = UrlQuery.of(MapUtil.of("a ", " ")).build(CharsetUtil.CHARSET_UTF_8);
|
||||
Assert.assertEquals("a%20=%20", a);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsePercentTest(){
|
||||
String queryStr = "a%2B=ccc";
|
||||
final UrlQuery query = UrlQuery.of(queryStr, null);
|
||||
Assert.assertEquals(queryStr, query.toString());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user